fix: bind knowledge maps to explicit regions
This commit is contained in:
1 parent
329a94d457
commit
90f75d41ae
15 files changed
+1126
-275
No files matched your search
+112
-49
@@ -35,6 +35,29 @@ GRAPH_POI_LABELS = {
|
||||
"BusStop": "公交站",
|
||||
}
|
||||
|
||||
# Projects imported from JSON do not have to use the historical Libo labels.
|
||||
# The city graph, for example, models every spatial business as ``Place`` and
|
||||
# stores its business type in ``place_type``. Keep this mapping in the map
|
||||
# adapter so every map-enabled project can use the same UI template.
|
||||
GRAPH_PLACE_TYPE_CATEGORIES = {
|
||||
"eat": "美食",
|
||||
"drink": "饮品",
|
||||
"hotel": "酒店",
|
||||
"mall": "商场",
|
||||
"sight": "景点",
|
||||
"transit": "交通设施",
|
||||
"transit_stop": "交通设施",
|
||||
"recreation": "体育休闲",
|
||||
"education": "科教文化",
|
||||
"medical": "医疗保健",
|
||||
"government": "政府机构",
|
||||
"enterprise": "公司企业",
|
||||
"life": "生活服务",
|
||||
"residential": "商务住宅",
|
||||
"facility": "公共设施",
|
||||
"poi": "其他地点",
|
||||
}
|
||||
|
||||
FOOD_ENRICHMENT_KEYS = (
|
||||
"food_fusion_status",
|
||||
"food_match_confidence",
|
||||
@@ -443,10 +466,12 @@ def _is_enterprise_travel_graph(graph_name: str) -> bool:
|
||||
|
||||
|
||||
def _resolve_spatial_graph_name(graph_name: str) -> str:
|
||||
"""Map the city project graph name to the materialized spatial POI graph."""
|
||||
lower = graph_name.lower()
|
||||
if graph_name == SPATIAL_GRAPH_NAME or lower.endswith("_spatial_v1"):
|
||||
return graph_name
|
||||
"""Resolve the explicitly paired city map store used by the legacy project.
|
||||
|
||||
``guiyang_new2`` is the semantic city graph while ``guiyang_spatial_v1`` is
|
||||
its map/POI store. Other map-enabled projects keep using their own graph,
|
||||
so imported bundles do not depend on a project-name convention.
|
||||
"""
|
||||
if graph_name == "guiyang_new2":
|
||||
return SPATIAL_GRAPH_NAME
|
||||
return graph_name
|
||||
@@ -670,6 +695,24 @@ def _graph_poi_enrichment(
|
||||
return labels, pick(FOOD_ENRICHMENT_KEYS), pick(HOTEL_ENRICHMENT_KEYS)
|
||||
|
||||
|
||||
def _graph_poi_business_categories(
|
||||
labels: list[str] | tuple[str, ...] | None,
|
||||
properties: dict[str, Any],
|
||||
) -> list[str]:
|
||||
categories = [
|
||||
GRAPH_POI_LABELS[label]
|
||||
for label in (labels or [])
|
||||
if label in GRAPH_POI_LABELS
|
||||
]
|
||||
type_label = str(properties.get("type_label") or "").strip()
|
||||
place_type = str(properties.get("place_type") or "").strip().lower()
|
||||
if type_label:
|
||||
categories.insert(0, type_label)
|
||||
elif place_type:
|
||||
categories.insert(0, GRAPH_PLACE_TYPE_CATEGORIES.get(place_type, place_type))
|
||||
return list(dict.fromkeys(category for category in categories if category))
|
||||
|
||||
|
||||
def _graph_poi_categories(graph_name: str) -> dict[str, list[str]]:
|
||||
db = FalkorDB(
|
||||
host=settings.falkordb_host,
|
||||
@@ -677,22 +720,26 @@ def _graph_poi_categories(graph_name: str) -> dict[str, list[str]]:
|
||||
)
|
||||
try:
|
||||
graph = db.select_graph(graph_name)
|
||||
rows = graph.query(
|
||||
"MATCH (n) "
|
||||
"WHERE n.element_id IS NOT NULL "
|
||||
"AND any(label IN labels(n) WHERE label IN "
|
||||
"['FoodPlace','Hotel','ScenicSpot','TransitFacility','BusStop']) "
|
||||
"RETURN n.element_id, labels(n)"
|
||||
).result_set
|
||||
result: dict[str, list[str]] = {}
|
||||
for element_id, labels in rows:
|
||||
categories = [
|
||||
GRAPH_POI_LABELS[label]
|
||||
for label in (labels or [])
|
||||
if label in GRAPH_POI_LABELS
|
||||
]
|
||||
if element_id and categories:
|
||||
result[str(element_id)] = categories
|
||||
page_size = 5000
|
||||
offset = 0
|
||||
while True:
|
||||
rows = graph.query(
|
||||
"MATCH (n) "
|
||||
"WHERE n.element_id IS NOT NULL "
|
||||
"AND coalesce(n.lng,n.longitude) IS NOT NULL "
|
||||
"AND coalesce(n.lat,n.latitude) IS NOT NULL "
|
||||
"RETURN n.element_id, labels(n), properties(n) "
|
||||
f"ORDER BY n.element_id SKIP {offset} LIMIT {page_size}"
|
||||
).result_set
|
||||
for element_id, labels, raw_properties in rows:
|
||||
properties = raw_properties if isinstance(raw_properties, dict) else {}
|
||||
categories = _graph_poi_business_categories(labels, properties)
|
||||
if element_id and categories:
|
||||
result[str(element_id)] = categories
|
||||
if len(rows) < page_size:
|
||||
break
|
||||
offset += page_size
|
||||
return result
|
||||
finally:
|
||||
db.close()
|
||||
@@ -715,16 +762,14 @@ def _graph_map_poi_items(rows: list[list[Any]]) -> list[dict[str, Any]]:
|
||||
items: list[dict[str, Any]] = []
|
||||
for node_id, labels, raw_properties in rows:
|
||||
properties = raw_properties if isinstance(raw_properties, dict) else {}
|
||||
lng = properties.get("lng")
|
||||
lat = properties.get("lat")
|
||||
lng = properties.get("lng", properties.get("longitude"))
|
||||
lat = properties.get("lat", properties.get("latitude"))
|
||||
if lng is None or lat is None:
|
||||
continue
|
||||
categories = [
|
||||
GRAPH_POI_LABELS[label]
|
||||
for label in (labels or [])
|
||||
if label in GRAPH_POI_LABELS
|
||||
]
|
||||
category = str(properties.get("type_label") or (categories[0] if categories else "其他地点"))
|
||||
categories = _graph_poi_business_categories(labels, properties)
|
||||
if not categories:
|
||||
continue
|
||||
category = categories[0]
|
||||
element_id = str(
|
||||
properties.get("element_id")
|
||||
or node_id
|
||||
@@ -744,6 +789,8 @@ def _graph_map_poi_items(rows: list[list[Any]]) -> list[dict[str, Any]]:
|
||||
"address": str(properties.get("address") or ""),
|
||||
"district": str(properties.get("district") or ""),
|
||||
"city": str(properties.get("city") or ""),
|
||||
"province": str(properties.get("province") or ""),
|
||||
"adcode": str(properties.get("adcode") or ""),
|
||||
"towncode": str(properties.get("towncode") or ""),
|
||||
"town_name": str(properties.get("town_name") or ""),
|
||||
"zone_id": str(properties.get("zone_id") or ""),
|
||||
@@ -756,15 +803,23 @@ def _graph_map_poi_items(rows: list[list[Any]]) -> list[dict[str, Any]]:
|
||||
def _read_graph_map_pois(graph_name: str) -> list[dict[str, Any]]:
|
||||
db = FalkorDB(host=settings.falkordb_host, port=settings.falkordb_port)
|
||||
try:
|
||||
rows = db.select_graph(graph_name).query(
|
||||
"MATCH (n) "
|
||||
"WHERE n.lng IS NOT NULL AND n.lat IS NOT NULL "
|
||||
"AND any(label IN labels(n) WHERE label IN "
|
||||
"['FoodPlace','Hotel','ScenicSpot','TransitFacility','BusStop']) "
|
||||
"RETURN n.__kg_node_id,labels(n),properties(n) "
|
||||
"ORDER BY n.name LIMIT 15000"
|
||||
).result_set
|
||||
return _graph_map_poi_items(rows)
|
||||
graph = db.select_graph(graph_name)
|
||||
items: list[dict[str, Any]] = []
|
||||
page_size = 5000
|
||||
offset = 0
|
||||
while True:
|
||||
rows = graph.query(
|
||||
"MATCH (n) "
|
||||
"WHERE coalesce(n.lng,n.longitude) IS NOT NULL "
|
||||
"AND coalesce(n.lat,n.latitude) IS NOT NULL "
|
||||
"RETURN n.__kg_node_id,labels(n),properties(n) "
|
||||
f"ORDER BY n.name,n.element_id SKIP {offset} LIMIT {page_size}"
|
||||
).result_set
|
||||
items.extend(_graph_map_poi_items(rows))
|
||||
if len(rows) < page_size:
|
||||
break
|
||||
offset += page_size
|
||||
return items
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@@ -899,12 +954,16 @@ def _graph_poi_detail_payload(
|
||||
or properties.get("gaode_poi_id")
|
||||
or ""
|
||||
)
|
||||
categories = _graph_poi_business_categories(labels, properties)
|
||||
lng = properties.get("lng", properties.get("longitude"))
|
||||
lat = properties.get("lat", properties.get("latitude"))
|
||||
return {
|
||||
"graph_name": graph_name,
|
||||
"id": element_id,
|
||||
"gaode_poi_id": str(properties.get("gaode_poi_id") or ""),
|
||||
"name": str(properties.get("name") or "未命名POI"),
|
||||
"category": str(properties.get("type_label") or "其他地点"),
|
||||
"category": categories[0] if categories else "其他地点",
|
||||
"categories": categories or ["其他地点"],
|
||||
"place_type": str(properties.get("place_type") or "poi"),
|
||||
"business_subcategory": raw.get("business_subcategory") or "",
|
||||
"scenic_type": raw.get("scenic_type") or properties.get("scenic_type") or "",
|
||||
@@ -920,8 +979,8 @@ def _graph_poi_detail_payload(
|
||||
"typecode": str(properties.get("typecode") or ""),
|
||||
"scan_hit_count": raw.get("scan_hit_count") or 0,
|
||||
"matched_scan_types": raw.get("matched_scan_types") or [],
|
||||
"lng": float(properties.get("lng") or 0),
|
||||
"lat": float(properties.get("lat") or 0),
|
||||
"lng": float(lng or 0),
|
||||
"lat": float(lat or 0),
|
||||
"province": str(properties.get("province") or ""),
|
||||
"city": str(properties.get("city") or ""),
|
||||
"district": str(properties.get("district") or ""),
|
||||
@@ -981,8 +1040,8 @@ async def map_pois(
|
||||
async with conn.cursor() as cur:
|
||||
await cur.execute(
|
||||
f"""SELECT p.element_id, p.gaode_poi_id, p.name, p.type_label,
|
||||
p.place_type, p.lng, p.lat, p.address, p.district,
|
||||
p.city, p.towncode, p.town_name,
|
||||
p.place_type, p.lng, p.lat, p.address, p.province,
|
||||
p.district, p.city, p.adcode, p.towncode, p.town_name,
|
||||
z.zone_id, z.zone_name
|
||||
FROM {s}.amap_spatial_pois p
|
||||
LEFT JOIN {s}.poi_zone_assignments z
|
||||
@@ -991,18 +1050,20 @@ async def map_pois(
|
||||
AND z.zone_set_id = %s
|
||||
WHERE p.graph_name=%s
|
||||
ORDER BY p.type_label, p.name
|
||||
LIMIT 15000""",
|
||||
LIMIT 100000""",
|
||||
(LIBO_ZONE_SET_ID, graph_name),
|
||||
)
|
||||
rows = await cur.fetchall()
|
||||
if rows:
|
||||
try:
|
||||
graph_categories = await asyncio.to_thread(
|
||||
_graph_poi_categories,
|
||||
graph_name,
|
||||
)
|
||||
except Exception: # noqa: BLE001 - relational points remain usable
|
||||
graph_categories = {}
|
||||
graph_categories: dict[str, list[str]] = {}
|
||||
if graph_name != SPATIAL_GRAPH_NAME:
|
||||
try:
|
||||
graph_categories = await asyncio.to_thread(
|
||||
_graph_poi_categories,
|
||||
graph_name,
|
||||
)
|
||||
except Exception: # noqa: BLE001 - relational points remain usable
|
||||
graph_categories = {}
|
||||
items = [
|
||||
{
|
||||
"id": row["element_id"],
|
||||
@@ -1017,8 +1078,10 @@ async def map_pois(
|
||||
"lng": float(row["lng"]),
|
||||
"lat": float(row["lat"]),
|
||||
"address": row["address"] or "",
|
||||
"province": row["province"] or "",
|
||||
"district": row["district"] or "",
|
||||
"city": row["city"] or "",
|
||||
"adcode": row["adcode"] or "",
|
||||
"towncode": row["towncode"] or "",
|
||||
"town_name": row["town_name"] or "",
|
||||
"zone_id": row["zone_id"] or "",
|
||||
|
||||
Reference in new issue
Block a user