Neo4j 查询完整路径



我有以下结构。

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`)

架构示例

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

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

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

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

不幸的是,这不是一个非常漂亮的方法,它基本上归结为收集 :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的初始匹配应该来自你words集合中第一个w的匹配时,所以它首先从所有 :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 节点的初始匹配是过滤其余单词关系之前的最小起始集。

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

有许多 apoc 程序可以帮助您解决这个问题。

下面是一个可能适合您的示例。在此示例中,我假设不区分大小写的比较是可以的,您保留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. 要查找(不区分大小写)包含集合中所有单词(通过$words参数传递)的Sentence节点,您需要执行如下所示的 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;
    

相关内容

  • 没有找到相关文章

最新更新