【问题标题】:Neo4j query for complete pathsNeo4j 查询完整路径
【发布时间】:2017-05-27 08:57:39
【问题描述】:

我有以下结构。

CREATE 
(`0` :Sentence {`{text`:'This is a sentence'}}) ,
(`1` :Word {`{ text`:'This' }}) ,
(`2` :Word {`{text`:'is'}}) ,
(`3` :Sentence {`{'text'`:'Sam is a dog'}}) ,
(`0`)-[:`RELATED_TO`]->(`1`),
(`0`)-[:`RELATED_TO`]->(`2`),
(`3`)-[:`RELATED_TO`]->(`2`)

schema example

所以我的问题是这样的。我有一堆我已经分解成单词对象的句子。这些词对象都是唯一的,因此会指向不同的句子。如果我搜索一个单词,很容易找出与该单词相关的所有句子。如何构建查询以找出两个单词而不是一个单词的相同信息。

我想提交两个或更多单词并找到一条包含所有提交的单词的路径,以获取所有感兴趣的句子。

【问题讨论】:

    标签: neo4j path


    【解决方案1】:

    我只记得另一种可能效果更好的方法。将此查询中的 PROFILE 与其他查询的配置文件进行比较,看看它是否更适合您。

    WITH {myListOfWords} as wordList
    WITH wordList, size(wordList) as wordCnt
    MATCH (s)-[:RELATED_TO]->(w:Word) 
    WHERE w.text in wordList
    WITH s, wordCnt, count(DISTINCT w) as cnt
    WHERE wordCnt = cnt
    RETURN s
    

    【讨论】:

      【解决方案2】:

      不幸的是,这不是一个非常漂亮的方法,它基本上归结为收集 :Word 节点并使用 ALL() 谓词来确保您想要的模式适用于集合的所有元素。

      MATCH (w:Word) 
      WHERE w.text in {myListOfWords}
      WITH collect(w) as words
      MATCH (s:Sentence)
      WHERE ALL(word in words WHERE (s)-[:RELATED_TO]->(word))
      RETURN s
      

      让这变得丑陋的原因在于,规划器现在还不够聪明,无法推断当您说 MATCH (s:Sentence) WHERE ALL(word in words ... 时,s 的初始匹配应该来自您 @ 中第一个 w 的匹配987654325@ 集合,所以它首先从所有 :Sentence 节点开始,这是一个主要的性能损失。

      所以要解决这个问题,我们必须从words 集合的第一个显式匹配,然后将WHERE ALL() 用于剩余的集合。

      MATCH (w:Word) 
      WHERE w.text in {myListOfWords}
      WITH w, size(()-[:RELATED_TO]->(w)) as rels
      WITH w ORDER BY rels ASC
      WITH collect(w) as words
      WITH head(words) as head, tail(words) as words
      MATCH (s)-[:RELATED_TO]->(head)
      WHERE ALL(word in words WHERE (s)-[:RELATED_TO]->(word))
      RETURN s
      

      编辑:

      添加了一个优化,以根据传入的 :RELATED_TO 关系的程度对您的 w 节点进行排序(这是对极少数节点的度数查找),因为这意味着与您的 :Sentence 节点的初始匹配是最小的可能在过滤其余单词中的关系之前开始设置。

      【讨论】:

      • 谢谢。我将开始沿着这个兔子洞前进。我将 python 和 cypher 混合在一起,所以也许我可以将上述内容分解为一些较小的查询
      【解决方案3】:

      作为替代方案,您可以考虑使用manual indexing(也称为“旧索引”)而不是使用Word 节点和RELATED_TO 关系。手动索引支持使用lucene 进行“全文”搜索。

      有很多apoc procedures 可以帮助您解决这个问题。

      这是一个可能对您有用的示例。在此示例中,我假设不区分大小写的比较是可以的,您保留 Sentence 节点(及其 text 属性),并且您希望自动将所有 Sentence 节点的 text 属性添加到手动索引.

      1. 如果您使用的是neo4j 3.2+,则必须将此设置添加到neo4j.conf 文件中,以使一些昂贵的apoc.index 程序(如apoc.index.addAllNodes)可用:

        dbms.security.procedures.unrestricted=apoc.*
        
      2. 执行此 Cypher 代码以使用所有现有 Sentence 节点中的 text 文本初始化名为“WordIndex”的手动索引,并从那时起启用自动索引:

        CALL apoc.index.addAllNodes('WordIndex', {Sentence: ['text']}, {autoUpdate: true})
        YIELD label, property, nodeCount
        RETURN *;
        
      3. 要查找(不区分大小写)包含集合中所有单词的Sentence 节点(通过$words parameter 传递),您需要执行如下所示的Cypher 语句。 WITH 子句为您构建 lucene 查询字符串(例如,“foo AND bar”)。警告:由于 lucene 的特殊布尔术语(如“AND”和“OR”)总是大写,你应该确保你传入的单词是小写的(或者修改下面的WITH 子句以使用 TOLOWER()` 函数根据需要)。

        WITH REDUCE(s = $words[0], x IN $words[1..] | s + ' AND ' + x) AS q
        CALL apoc.index.search('WordIndex', q) YIELD node
        RETURN node;
        

      【讨论】:

        猜你喜欢
        • 2018-04-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多