2017-09-13 11 views
2

私の目標は、neo4jを使用して文書に対して2種類の検索を行うことです。私は私の例としてレシピ(ドキュメント)を使用します。 私は原料(キーワード)の手元に(ミルク、バター、小麦粉、塩、砂糖、卵...)、私は各レシピに添付された成分で私のデータベースにいくつかのレシピがあります。私は自分のリストを入力して2つの異なる結果を得たいと思います。 1つは、入力したすべての成分を最もよく含むレシピです。 2つ目は、すべての成分を一緒に含むレシピの組み合わせです。Neo4j検索のための文書、キーワード、単語のステムのデータモデル

考える:牛乳、バター、小麦粉、塩、砂糖、卵

は、最初のケースの検索結果は次のようになります。

1)シュガークッキー

2)バタークッキー

秒の結果は次のようになります。

1)フラットパンとGogel-Mogel

私はneo4jに挿入するレシピを読んでいます。各レシピの上部にある成分リストから成分を引き出しますが、レシピの指示も引き出します。私はこれらの違いを、60/40の材料リストに賛成して計量したいと思っています。

人が同じような言葉を入力する場合に備えて、それぞれの原料を茎にしたいと思います。

私はneo4jで良いデータモデルを思いつくのに苦労しています。私はユーザーが英語の食材を入れることを計画しており、私はそれらをバックグラウンドで茎にし、それを検索に使用します。

私が最初に考えただった: neo4j data model 1 これは私には直感的であるが、すべてのレシピを見つけるためにホップがたくさんあります。

次多分この: neo4j data model 2

茎が、私は関係の中でレシピIDを渡す必要があるでしょうから直接レシピになる(?右)実際の成分を取得します。

第3に、おそらくこれらを組み合わせることはできますか? 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番目のクエリにお役立てください。成分のリストが与えられている場合、与えられた成分を一緒に含むレシピの組み合わせが返されます。再度、感謝します!

答えて

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を行います。 –

関連する問題