2017-05-23 1 views
1

다음 구조가 있습니다.전체 경로에 대한 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`) 

schema example

그래서 제 질문은 이것이다. 나는 여러 단어 문장으로 분해 된 문장들을 가지고있다. 이 단어 개체는 모두 고유하므로 다른 문장을 가리 킵니다. 한 단어를 검색하면 단어가 관련된 모든 문장을 쉽게 알아낼 수 있습니다. 하나의 단어가 아닌 두 단어에 대해 동일한 정보를 찾기 위해 쿼리를 어떻게 구성 할 수 있습니까?

두 개 이상의 단어를 제출하고 제출 된 모든 단어가 포함 된 경로를 찾고 싶습니다.

답변

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의 초기 일치하여 words 컬렉션의 첫 번째 w에서 경기를 고려해야합니다 즉, 그래서 처음부터 문장 노드 (sentence node)가 시작된다.

이 문제를 해결하려면 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 관계 (이 매우 적은 노드에서 학위 조회입니다) 귀하의 : 문장 노드는 나머지 단어들과의 관계를 필터링하기 전에 가장 작은 가능한 시작 세트입니다.

+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 
0

대안으로 대신 Word 노드와 RELATED_TO 관계를 사용하는 (또한 "기존의 색인") manual indexing 사용을 고려할 수 있습니다. 수동 색인은 lucene을 사용하여 "fulltext"검색을 지원합니다.

많은 도움이되는 apoc procedures이 있습니다.

다음은 사용자에게 도움이 될만한 예입니다. 이 예에서는 대소 문자를 구별하지 않는 비교가 OK라고 가정하고 Sentence 노드 (및 그 노드의 text 속성)를 그대로 유지하고 모든 Sentence 노드의 속성을 수동 인덱스에 자동으로 추가하려고합니다.

  1. neo4j를 사용하는 경우 3.2+, 당신은 (같은 apoc.index.addAllNodes)를 비싼 apoc.index 절차를 확인하기 위해 neo4j.conf 파일에 사용할 수있는이 설정을 추가해야합니다 :

    dbms.security.procedures.unrestricted=apoc.* 
    
  2. text 텍스트 "WordIndex"라는 이름의 수동 인덱스를 초기화하는이 사이퍼 코드를 실행 기존의 모든 Sentence 노드에서, 그리고 그 시점에서 자동 인덱싱을 활성화하려면 :

    CALL apoc.index.addAllNodes('WordIndex', {Sentence: ['text']}, {autoUpdate: true}) 
    YIELD label, property, nodeCount 
    RETURN *; 
    
  3. 는 컬렉션의 모든 단어를 포함하는 Sentence 노드 (패스포트 (소문자를 구별 경우) 찾으려면 d를 $wordsparameter으로 바꾸면 아래와 같은 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;