【问题标题】:Neo4j Cypher filtering based on map parameters基于地图参数的 Neo4j Cypher 过滤
【发布时间】:2017-05-11 06:31:10
【问题描述】:

根据上一个问题:

Neo4j Cypher query structure and performance optimization Neo4j Cypher node filtering by pattern comprehension

最后我将查询重构为以下内容:

MATCH (parentD)-[:CONTAINS]->(childD:Decision) 
    WHERE id(parentD) = {decisionId} 
        MATCH (childD)<-[:SET_FOR]-(equalFilterValue)-[:SET_ON]->(equalFilterCharacteristic) 
            WHERE ALL(key IN keys({equalFilters}) WHERE id(equalFilterCharacteristic) = toInt(key) AND equalFilterValue.value = ({equalFilters}[key]))  
    WITH DISTINCT childD  
        MATCH (childD)<-[:SET_FOR]-(rangeFilterValue)-[:SET_ON]->(rangeFilterCharacteristic) 
            WHERE ALL(key IN keys({rangeFilters}) WHERE id(rangeFilterCharacteristic) = toInt(key) AND ({rangeFilters}[key])[0] <= rangeFilterValue.value <= ({rangeFilters}[key])[1]) 
WITH * MATCH (childD)-[ru:CREATED_BY]->(u:User)  
RETURN ru, u, childD AS decision 
SKIP 0 LIMIT 100

如果每个*filter type(map) 只有一个键,则此查询可以正常工作,例如:

queries.add(new InQuery(integerCharacteristic.getId(), 30));

queries.add(new InQuery(stringCharacteristic.getId(), "Two"));

但当我添加 2 个或更多条件时失败,例如:

queries.add(new InQuery(integerCharacteristic.getId(), 30));
queries.add(new InQuery(stringCharacteristic.getId(), "Two"));

以下查询未按预期工作,我的测试断言失败:

MATCH (parentD)-[:CONTAINS]->(childD:Decision) 
WHERE id(parentD) = {decisionId} 
    MATCH (childD)<-[:SET_FOR]-(inFilterValue)-[:SET_ON]->(inFilterCharacteristic) 
        WHERE ALL(key IN keys({inFilters}) WHERE id(inFilterCharacteristic) = toInt(key) AND ({inFilters}[key]) IN inFilterValue.value) 
WITH * MATCH (childD)-[ru:CREATED_BY]->(u:User)  
RETURN ru, u, childD AS decision 
SKIP 0 LIMIT 100

参数:

inFilters = {3153=30, 3151=Two}

为什么当inFilters map 包含 2 个或更多键时它不起作用以及如何使它起作用?

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    因此,由于这仅适用于 1 个键,让我们回顾一下当有 2 个键时,WHERE ALL 在做什么。

    WITH inFilters = {3153=30, 3151=Two}
    ....
    WHERE ALL(key IN keys({equalFilters}) 
        WHERE id(equalFilterCharacteristic) = toInt(key) 
        AND equalFilterValue.value = ({equalFilters}[key]))
    

    相当于

    WHERE id(equalFilterCharacteristic) = toInt(3153) 
    AND equalFilterValue.value = ({equalFilters}[3153]) 
    AND id(equalFilterCharacteristic) = toInt(3151) 
    AND equalFilterValue.value = ({equalFilters}[3151])
    

    问题在于,现在我们正在检查每个 equalFilterCharacteristic 的节点 id 是否同时等于 3153 和 3151。由于 Neo4j 仅使用实数作为节点 id,因此当有超过 1 个键时,上述语句基本上最终会减少到昂贵的 WHERE FALSE。因此,在上述情况下,WHERE ALL 永远不会为真。但是,如果至少 1 个检查组为真,则 WHERE ANY 将评估为真,并且等效于

    WHERE ( 
        id(equalFilterCharacteristic) = toInt(3153) 
        AND equalFilterValue.value = ({equalFilters}[3153]) 
    )
    OR 
    (
        id(equalFilterCharacteristic) = toInt(3151) 
        AND equalFilterValue.value = ({equalFilters}[3151]) 
    )
    

    当然,既然您知道要匹配的密钥,您可以跳过 ALL 并直接执行(不要认为您需要对 id() 进行 toInt(),但 id() 很长)

    WHERE equalFilterValue.value = ({equalFilters}[id(equalFilterCharacteristic)]) 
    

    【讨论】:

    • 感谢您的回答。所以换句话说 - 没有办法以这种方式实现这样的逻辑,我必须坚持使用以下票证stackoverflow.com/questions/43824894/…的原始方法?
    • @alexanoid 排序...这里的关键(双关语无意)是节点查找部分。仅使用地图检查,您必须遍历每个节点,检查它们的 id 是否是地图中的键,并检查值。如果你拉起像 (psudocode) id(node) IN map.keyset() 这样的节点,那么你不再需要为 map[node.id] 存在检查拉每个节点。不过,Cypher 是一种描述性语言,因此将内容隐藏在地图中会使 Cypher 更难计划更有效的查询。因此,地图永远不会完全等同于另一种查询格式。 (除非您对其进行完整循环)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多