fix(memory): add coalesce defaults for activation_value and related node properties
- Add coalesce fallbacks for importance_score, activation_value, and access_count in statement, entity, weak entity, strong entity, and memory summary MERGE queries to prevent null values on new nodes - Set activation_value default to coalesce(importance_score, 0.5) for consistency with the forgetting/activation scoring logic - Suppress Neo4j UNRECOGNIZED property key notifications in driver init since missing keys like last_access_time and activation_value are expected for newly created nodes
This commit is contained in:
@@ -42,6 +42,9 @@ SET s += {
|
|||||||
last_access_time: statement.last_access_time,
|
last_access_time: statement.last_access_time,
|
||||||
access_count: statement.access_count
|
access_count: statement.access_count
|
||||||
}
|
}
|
||||||
|
SET s.importance_score = coalesce(s.importance_score, 0.5),
|
||||||
|
s.activation_value = coalesce(s.activation_value, s.importance_score, 0.5),
|
||||||
|
s.access_count = coalesce(s.access_count, 0)
|
||||||
RETURN s.id AS uuid
|
RETURN s.id AS uuid
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -120,7 +123,7 @@ SET e.name = CASE WHEN entity.name IS NOT NULL AND entity.name <> '' THEN entity
|
|||||||
END
|
END
|
||||||
END,
|
END,
|
||||||
e.importance_score = CASE WHEN entity.importance_score IS NOT NULL THEN entity.importance_score ELSE coalesce(e.importance_score, 0.5) END,
|
e.importance_score = CASE WHEN entity.importance_score IS NOT NULL THEN entity.importance_score ELSE coalesce(e.importance_score, 0.5) END,
|
||||||
e.activation_value = CASE WHEN entity.activation_value IS NOT NULL THEN entity.activation_value ELSE e.activation_value END,
|
e.activation_value = CASE WHEN entity.activation_value IS NOT NULL THEN entity.activation_value ELSE coalesce(e.activation_value, e.importance_score, 0.5) END,
|
||||||
e.access_history = CASE WHEN entity.access_history IS NOT NULL THEN entity.access_history ELSE coalesce(e.access_history, []) END,
|
e.access_history = CASE WHEN entity.access_history IS NOT NULL THEN entity.access_history ELSE coalesce(e.access_history, []) END,
|
||||||
e.last_access_time = CASE WHEN entity.last_access_time IS NOT NULL THEN entity.last_access_time ELSE e.last_access_time END,
|
e.last_access_time = CASE WHEN entity.last_access_time IS NOT NULL THEN entity.last_access_time ELSE e.last_access_time END,
|
||||||
e.access_count = CASE WHEN entity.access_count IS NOT NULL THEN entity.access_count ELSE coalesce(e.access_count, 0) END,
|
e.access_count = CASE WHEN entity.access_count IS NOT NULL THEN entity.access_count ELSE coalesce(e.access_count, 0) END,
|
||||||
@@ -165,6 +168,7 @@ SET e += {
|
|||||||
}
|
}
|
||||||
// Independent weak flag,仅标记弱关系,不再维护 relations 聚合字段
|
// Independent weak flag,仅标记弱关系,不再维护 relations 聚合字段
|
||||||
SET e.is_weak = true
|
SET e.is_weak = true
|
||||||
|
SET e.activation_value = coalesce(e.activation_value, 0.5)
|
||||||
RETURN e.id AS id
|
RETURN e.id AS id
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -175,10 +179,12 @@ MERGE (s:ExtractedEntity {id: item.source_id, run_id: item.run_id})
|
|||||||
SET s += {name: item.subject, end_user_id: item.end_user_id, run_id: item.run_id}
|
SET s += {name: item.subject, end_user_id: item.end_user_id, run_id: item.run_id}
|
||||||
// Independent strong flag
|
// Independent strong flag
|
||||||
SET s.is_strong = true
|
SET s.is_strong = true
|
||||||
|
SET s.activation_value = coalesce(s.activation_value, 0.5)
|
||||||
MERGE (o:ExtractedEntity {id: item.target_id, run_id: item.run_id})
|
MERGE (o:ExtractedEntity {id: item.target_id, run_id: item.run_id})
|
||||||
SET o += {name: item.object, end_user_id: item.end_user_id, run_id: item.run_id}
|
SET o += {name: item.object, end_user_id: item.end_user_id, run_id: item.run_id}
|
||||||
// Independent strong flag
|
// Independent strong flag
|
||||||
SET o.is_strong = true
|
SET o.is_strong = true
|
||||||
|
SET o.activation_value = coalesce(o.activation_value, 0.5)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -739,7 +745,7 @@ SET m += {
|
|||||||
summary_embedding: summary.summary_embedding,
|
summary_embedding: summary.summary_embedding,
|
||||||
config_id: summary.config_id,
|
config_id: summary.config_id,
|
||||||
importance_score: CASE WHEN summary.importance_score IS NOT NULL THEN summary.importance_score ELSE coalesce(m.importance_score, 0.5) END,
|
importance_score: CASE WHEN summary.importance_score IS NOT NULL THEN summary.importance_score ELSE coalesce(m.importance_score, 0.5) END,
|
||||||
activation_value: CASE WHEN summary.activation_value IS NOT NULL THEN summary.activation_value ELSE m.activation_value END,
|
activation_value: CASE WHEN summary.activation_value IS NOT NULL THEN summary.activation_value ELSE coalesce(m.activation_value, m.importance_score, 0.5) END,
|
||||||
access_history: CASE WHEN summary.access_history IS NOT NULL THEN summary.access_history ELSE coalesce(m.access_history, []) END,
|
access_history: CASE WHEN summary.access_history IS NOT NULL THEN summary.access_history ELSE coalesce(m.access_history, []) END,
|
||||||
last_access_time: CASE WHEN summary.last_access_time IS NOT NULL THEN summary.last_access_time ELSE m.last_access_time END,
|
last_access_time: CASE WHEN summary.last_access_time IS NOT NULL THEN summary.last_access_time ELSE m.last_access_time END,
|
||||||
access_count: CASE WHEN summary.access_count IS NOT NULL THEN summary.access_count ELSE coalesce(m.access_count, 0) END
|
access_count: CASE WHEN summary.access_count IS NOT NULL THEN summary.access_count ELSE coalesce(m.access_count, 0) END
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ Classes:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from typing import Any, List, Dict
|
from typing import Any, List, Dict
|
||||||
|
import logging
|
||||||
|
|
||||||
from neo4j import AsyncGraphDatabase, basic_auth
|
from neo4j import AsyncGraphDatabase, basic_auth
|
||||||
from neo4j.time import DateTime as Neo4jDateTime, Date as Neo4jDate, Time as Neo4jTime, Duration as Neo4jDuration
|
from neo4j.time import DateTime as Neo4jDateTime, Date as Neo4jDate, Time as Neo4jTime, Duration as Neo4jDuration
|
||||||
|
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def _convert_neo4j_types(value: Any) -> Any:
|
def _convert_neo4j_types(value: Any) -> Any:
|
||||||
"""递归将 neo4j 原生时间类型转为 Python 原生类型 / ISO 字符串,确保可被 json.dumps 序列化。"""
|
"""递归将 neo4j 原生时间类型转为 Python 原生类型 / ISO 字符串,确保可被 json.dumps 序列化。"""
|
||||||
@@ -67,7 +70,12 @@ class Neo4jConnector:
|
|||||||
)
|
)
|
||||||
self.driver = AsyncGraphDatabase.driver(
|
self.driver = AsyncGraphDatabase.driver(
|
||||||
uri,
|
uri,
|
||||||
auth=basic_auth(username, password)
|
auth=basic_auth(username, password),
|
||||||
|
# 抑制属性键不存在的 UNRECOGNIZED 分类通知警告(如 01N52)
|
||||||
|
# last_access_time 等属性在节点被检索命中后才写入,
|
||||||
|
# activation_value 在新节点创建后可能尚未被计算,
|
||||||
|
# 全新数据库或清空数据后这些属性键不存在是正常业务行为
|
||||||
|
notifications_disabled_classifications=["UNRECOGNIZED"],
|
||||||
)
|
)
|
||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user