我有以下结构。
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`)
所以我的问题是这个。我有一堆句子,我已经分解成单词对象。这些单词对象都是唯一的,因此会指向不同的句子。如果我搜索一个单词,很容易找出与单词相关的所有句子。如何构造查询以找出两个单词而不是一个单词的相同信息。
我想提交两个或更多单词,并找到一条路径,其中包含所有提交的单词,并将所有感兴趣的句子提取出来。
答案 0 :(得分: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
答案 1 :(得分:0)
不幸的是,这不是一个非常漂亮的方法,它主要归结为收集: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
集合中的words
,因此它从所有节点开始:首先是句子节点,这是主要的性能影响。
为了解决这个问题,我们必须从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
编辑:
添加了一个优化,以根据传入的程度对w
个节点进行排序:RELATED_TO关系(这是极少数节点上的度数查找),因为这意味着与您的:Sentence节点的初始匹配是在从其他单词过滤关系之前,可能的最小起始集。
答案 2 :(得分:0)
作为替代方案,您可以考虑使用manual indexing(也称为“遗留索引”),而不是使用Word
节点和RELATED_TO
关系。手动索引使用lucene支持“全文”搜索。
有很多apoc procedures可以帮助您解决此问题。
这是一个可能适合您的示例。在此示例中,我假设不区分大小写的比较正常,您保留Sentence
个节点(及其text
属性),并且您希望自动添加所有text
属性Sentence
1}}节点到手动索引。
如果您使用的是neo4j 3.2+,则必须将此设置添加到neo4j.conf
文件中,以便使一些昂贵的apoc.index
程序(如apoc.index.addAllNodes
)可用:
dbms.security.procedures.unrestricted=apoc.*
执行此Cypher代码,使用所有现有text
节点中的Sentence
文本初始化名为“WordIndex”的手动索引,并启用从该点开始的自动索引:
CALL apoc.index.addAllNodes('WordIndex', {Sentence: ['text']}, {autoUpdate: true})
YIELD label, property, nodeCount
RETURN *;
要查找(不区分大小写)包含集合中所有单词的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;