2017-09-13 2 views
2

내 목표는 neo4j를 사용하여 문서에 대해 두 가지 종류의 검색을 수행하는 것입니다. 필자는 예를 들어 요리법 (문서)을 사용하겠습니다. (우유, 버터, 밀가루, 소금, 설탕, 달걀 ...) 재료 목록 (핵심 단어)을 가지고 있고 각 조리법에 첨부 된 재료로 데이터베이스에 일부 요리법이 있습니다. 내 목록을 입력하고 두 가지 결과를 얻고 싶습니다. 하나는 내가 입력 한 모든 재료를 가장 많이 포함하는 조리법이 될 것입니다. 두 번째는 모든 재료를 함께 포함하는 요리법의 조합입니다.Neo4j 검색을위한 문서, 키워드 및 단어 스템의 데이터 모델

을 감안할 때 : 우유, 버터, 밀가루, 소금, 설탕, 계란

첫 번째 경우에 대한 검색 결과는 다음과 같을 수 있습니다

1) 설탕 쿠키

2) 버터 쿠키

두 번째에 대한 결과는 다음과 같을 수 있습니다

1) 평면 빵과 Gogel - Mogel

neo4j에 삽입 할 요리법을 읽고 각 요리법 상단의 재료 목록에서 재료를 꺼내었지만 레시피 지침에서 가져 왔습니다. 나는 이것들을 다르게, 아마도 성분 목록에 찬성하여 60/40의 무게를 달고 싶다.

사람들이 유사한 단어를 입력 할 경우를 대비하여 각 성분을 줄이고 싶습니다.

저는 neo4j에서 좋은 데이터 모델을 찾기 위해 고심하고 있습니다. 나는 사용자가 영어 성분을 입력 할 것을 계획하고, 나는 그들을 백그라운드에서 줄여서 검색에 사용한다.

나의 첫 번째 생각은 : neo4j data model 1 이것은 직관적이지만 모든 요리법을 찾기위한 많은 호프입니다.

다음 어쩌면이 : neo4j data model 2

줄기,하지만 난 관계에 조리법 ID를 통과 할 필요가에서 직접 조리법에 도달 (? 오른쪽) 실제 재료를 얻을 수 있습니다.

셋째, 아마도 다음과 같이 결합 할 수 있습니까? neo4j data model 3 하지만 중복되는 부분이 많습니다.

//Create 4 recipes 
create (r1:Recipe {rid:'1', title:'Sugar cookies'}), (r2:Recipe {rid:'2', title:'Butter cookies'}), 
(r3:Recipe {rid:'3', title:'Flat bread'}), (r4:Recipe {rid:'4', title:'Gogel-Mogel'}) 

//Adding some ingredients 
merge (i1:Ingredient {ingredient:"salted butter"}) 
merge (i2:Ingredient {ingredient:"white sugar"}) 
merge (i3:Ingredient {ingredient:"brown sugar"}) 
merge (i4:Ingredient {ingredient:"all purpose flour"}) 
merge (i5:Ingredient {ingredient:"iodized salt"}) 
merge (i6:Ingredient {ingredient:"eggs"}) 
merge (i7:Ingredient {ingredient:"milk"}) 
merge (i8:Ingredient {ingredient:"powdered sugar"}) 
merge (i9:Ingredient {ingredient:"wheat flour"}) 
merge (i10:Ingredient {ingredient:"bananas"}) 
merge (i11:Ingredient {ingredient:"chocolate chips"}) 
merge (i12:Ingredient {ingredient:"raisins"}) 
merge (i13:Ingredient {ingredient:"unsalted butter"}) 
merge (i14:Ingredient {ingredient:"wheat flour"}) 
merge (i15:Ingredient {ingredient:"himalayan salt"}) 
merge (i16:Ingredient {ingredient:"chocolate bars"}) 
merge (i17:Ingredient {ingredient:"vanilla flavoring"}) 
merge (i18:Ingredient {ingredient:"vanilla"}) 

//Stems added to each ingredient 
merge (i1)<-[:STEM_OF]-(s1:Stem {stem:"butter"}) 
merge (i2)<-[:STEM_OF]-(s2:Stem {stem:"sugar"}) 
merge (i3)<-[:STEM_OF]-(s2) 
merge (i4)<-[:STEM_OF]-(s4:Stem {stem:"flour"}) 
merge (i5)<-[:STEM_OF]-(s5:Stem {stem:"salt"}) 
merge (i6)<-[:STEM_OF]-(s6:Stem {stem:"egg"}) 
merge (i7)<-[:STEM_OF]-(s7:Stem {stem:"milk"}) 
merge (i8)<-[:STEM_OF]-(s2) 
merge (i9)<-[:STEM_OF]-(s4) 
merge (i10)<-[:STEM_OF]-(s10:Stem {stem:"banana"}) 

merge (i11)<-[:STEM_OF]-(s11:Stem {stem:"chocolate"}) 
merge (i12)<-[:STEM_OF]-(s12:Stem {stem:"raisin"}) 
merge (i13)<-[:STEM_OF]-(s1) 
merge (i14)<-[:STEM_OF]-(s4) 
merge (i15)<-[:STEM_OF]-(s5) 
merge (i16)<-[:STEM_OF]-(s11) 
merge (i17)<-[:STEM_OF]-(s13:Stem {stem:"vanilla"}) 
merge (i18)<-[:STEM_OF]-(s13) 


create (r1)<-[:INGREDIENTS_LIST{weight:.7}]-(i1) 
create (r1)<-[:INGREDIENTS_LIST{weight:.6}]-(i2)  
create (r1)<-[:INGREDIENTS_LIST{weight:.5}]-(i4) 
create (r1)<-[:INGREDIENTS_LIST{weight:.4}]-(i5) 
create (r1)<-[:INGREDIENTS_LIST{weight:.4}]-(i6) 
create (r1)<-[:INGREDIENTS_LIST{weight:.2}]-(i7) 
create (r1)<-[:INGREDIENTS_LIST{weight:.1}]-(i18) 

create (r2)<-[:INGREDIENTS_LIST{weight:.7}]-(i1) 
create (r2)<-[:INGREDIENTS_LIST{weight:.6}]-(i3)  
create (r2)<-[:INGREDIENTS_LIST{weight:.5}]-(i4) 
create (r2)<-[:INGREDIENTS_LIST{weight:.4}]-(i5) 
create (r2)<-[:INGREDIENTS_LIST{weight:.3}]-(i6) 
create (r2)<-[:INGREDIENTS_LIST{weight:.2}]-(i7) 
create (r2)<-[:INGREDIENTS_LIST{weight:.1}]-(i18) 

create (r3)<-[:INGREDIENTS_LIST{weight:.7}]-(i1) 
create (r3)<-[:INGREDIENTS_LIST{weight:.6}]-(i5) 
create (r3)<-[:INGREDIENTS_LIST{weight:.5}]-(i7) 
create (r3)<-[:INGREDIENTS_LIST{weight:.4}]-(i9) 

create (r4)<-[:INGREDIENTS_LIST{weight:.6}]-(i2) 
create (r4)<-[:INGREDIENTS_LIST{weight:.5}]-(i6) 



create (r1)<-[:INGREDIENTS_INSTR{weight:.2}]-(i1) 
create (r1)<-[:INGREDIENTS_INSTR{weight:.2}]-(i2) 
create (r1)<-[:INGREDIENTS_INSTR{weight:.2}]-(i4) 
create (r1)<-[:INGREDIENTS_INSTR{weight:.2}]-(i5) 
create (r1)<-[:INGREDIENTS_INSTR{weight:.1}]-(i6) 
create (r1)<-[:INGREDIENTS_INSTR{weight:.1}]-(i7) 


create (r2)<-[:INGREDIENTS_INSTR{weight:.3}]-(i1) 
create (r2)<-[:INGREDIENTS_INSTR{weight:.2}]-(i3) 
create (r2)<-[:INGREDIENTS_INSTR{weight:.2}]-(i4) 
create (r2)<-[:INGREDIENTS_INSTR{weight:.2}]-(i5) 
create (r2)<-[:INGREDIENTS_INSTR{weight:.2}]-(i6) 
create (r2)<-[:INGREDIENTS_INSTR{weight:.1}]-(i7) 


create (r3)<-[:INGREDIENTS_INSTR{weight:.3}]-(i1) 
create (r3)<-[:INGREDIENTS_INSTR{weight:.3}]-(i5) 
create (r3)<-[:INGREDIENTS_INSTR{weight:.1}]-(i7) 
create (r3)<-[:INGREDIENTS_INSTR{weight:.1}]-(i9) 

create (r4)<-[:INGREDIENTS_INSTR{weight:.3}]-(i2) 
create (r4)<-[:INGREDIENTS_INSTR{weight:.3}]-(i6) 

과 위의 문장과 neo4j 콘솔에 대한 링크 : 여러 관계에 관심 neo4j 않습니다 얼마나 http://console.neo4j.org/?id=3o8y44

여기

는 처음 아이디어를 만들 수있는 몇 가지 CYPHER 문입니까? 또한 하나의 성분만을 섭취 할 수 있습니다.하지만 하나 이상의 성분이 들어있는 요리법을 얻기 위해 어떻게 쿼리를 작성해야합니까?

편집 : 마이클! 그게 나를 더 멀리 잡았어. 나는 이것에 당신의 응답을 확장 할 수 있었다 :

WITH split("egg, sugar, chocolate, milk, flour, salt",", ") as terms UNWIND 
terms as term MATCH (stem:Stem {stem:term})-[:STEM_OF]-> 
(ingredient:Ingredient)-[lst:INGREDIENTS_LIST]->(r:Recipe) WITH r, 
size(terms) - count(distinct stem) as notCovered, sum(lst.weight) as weight, 
collect(distinct stem.stem) as matched RETURN r , notCovered,matched, weight 
ORDER BY notCovered ASC, weight DESC 

그리고 일치 된 성분의 명부 및 무게를 얻었다.INGREDIENTS_INSTR 관계의 가중치도 표시하도록 쿼리를 어떻게 변경하면 동시에 두 가중치를 모두 계산에 사용할 수 있습니까? [lst : INGREDIENTS_LIST | INGREDIENTS_INSTR]은 내가 원하는 것이 아닙니다.

편집 :

이, 작동하는 것 같다가 올바른

?

WITH split("egg, sugar, chocolate, milk, flour, salt",", ") as terms UNWIND 
terms as term MATCH (stem:Stem {stem:term})-[:STEM_OF]-> 
(ingredient:Ingredient)-[lstl:INGREDIENTS_LIST]->(r:Recipe)<- 
[lsti:INGREDIENTS_INSTR]-(ingredient:Ingredient) WITH r, size(terms) - 
count(distinct stem) as notCovered, sum(lsti.weight) as wi, sum(lstl.weight) 
as wl, collect(distinct stem.stem) as matched RETURN r , 
notCovered,matched, wl+wi ORDER BY notCovered ASC, wl+wi DESC 

또한 두 번째 쿼리를 도와 줄 수 있습니까? 재료 목록이 주어지면 주어진 재료를 함께 포함하는 조리법 조합이 반환됩니다. 다시 한 번 감사드립니다!

답변

2

귀하의 버전 1과 함께 갈 것입니다.

추가 홉에 대해 걱정하지 마십시오. 레시피와 실제 성분 간의 관계에 대한 양/무게에 대한 정보를 넣으십시오.

여러 관계를 가질 수 있습니다. 여기

는 모든 재료를 가지고 어떤 조리법이 없기 때문에 그 데이터 집합 작동하지 않습니다, 예를 들어 쿼리입니다 :

WITH split("milk, butter, flour, salt, sugar, eggs",", ") as terms 
UNWIND terms as term 
MATCH (stem:Stem {stem:term})-[:STEM_OF]->(ingredient:Ingredient)-->(r:Recipe) 
WITH r, size(terms) - count(distinct stem) as notCovered 
RETURN r ORDER BY notCovered ASC LIMIT 2 

+-----------------------------------------+ 
| r          | 
+-----------------------------------------+ 
| Node[0]{rid:"1",title:"Sugar cookies"} | 
| Node[1]{rid:"2",title:"Butter cookies"} | 
+-----------------------------------------+ 
2 rows 

큰 데이터 세트에 대한 최적화 될 것이다 다음

그리고 당신이 먼저 모든 재료를 찾은 다음, 레시피가 가장 낮은 선택도를 가진 레시피에 붙어 있습니다.

그리고 각 레시피에 대해 나머지 성분을 확인하십시오.

WITH split("milk, butter, flour, salt, sugar, eggs",", ") as terms 
MATCH (stem:Stem) WHERE stem.stem IN terms 
// highest selective stem first 
WITH stem, terms ORDER BY size((stem)-[:STEM_OF]->()) ASC 
WITH terms, collect(stem) as stems 
WITH head(stems) first, tail(stems) as rest, terms 
MATCH (first)-[:STEM_OF]->(ingredient:Ingredient)-->(r:Recipe) 
WHERE size[other IN rest WHERE (other)-[:STEM_OF]->(:Ingredient)-->(r)] as covered 
WITH r, size(terms) - 1 - covered as notCovered 
RETURN r ORDER BY notCovered ASC LIMIT 2 
+0

마지막 부분에 답이 누락 되었습니까? 콜론 이후에요? – Oleg

+0

Q1에 대해 편집하면 Q2가 나중에 수행됩니다. –

관련 문제