2017-01-30 1 views
2

私のグラフは、このように設定されている有効な場合:私は、すべての関係を確認したがされているもののみから結果を返すために、動的CYPHERクエリを構築しようとしているサイファー問合せは、いずれか一方が

(:User)-[:LIVES_IN_COUNTRY]->(:Country) 
(:User)-[:LIVES_IN_STATE]->(:State) 
(:User)-[:LIVES_IN_CITY]->(:City) 

有効

たとえば、国名と州名のみがわかっている場合は、その国と州の有効な名前と市の "Not Available"を渡します。私はこのようなものを試しました:

Match(n:User) 
Match(n)-[:LIVES_IN_COUNTRY]->(:Country {name:'Canada'}) 
Match(n)-[:LIVES_IN_STATE]->(:State {name:'Ontario'}) 
Match(n)-[:LIVES_IN_CITY]->(:City {name:'Not Available'}) 

しかし、この場合、何も返されません。この場合、市区町村名がご利用いただけない場合、カナダとオンタリオ州のユーザーを取得するにはどうすればよいですか?

おそらくそれは、別々のCYPHERクエリを使用して可能であるが、それは1つの可能性CYPHERクエリ内

を処理する場合、私は思っていた私は、オプションの使用しようとしましたが、それはようにすべてのすべての国のユーザー、州とを返します。それは、オプションまたはクエリ

で何か間違っ
Match(n:User) 
OPTIONAL Match (n)-[:LIVES_IN_COUNTRY]->(:Country{name:'Canada'}) 
OPTIONAL Match (n)-[:LIVES_IN_STATE]->(:State {name:'Ontario'}) 
OPTIONAL Match (n)-[:LIVES_IN_CITY]->(:City {name:'Not Available'}) 
Return n.username,n.country, n.state, n.city 

答えて

2

で可能であるかどうかわから国、州、および都市の代わりにMATCHのOPTIONAL MATCHを使用してみてくださいません。これは、結果から行を削除することなく不一致を処理します。私は、これは一般的なクエリではなく、特定のユーザーから照会されたものであったことを見逃し

EDIT

ベスト・アプローチは、データが利用できないときにマッチを完全に中止することです(Javaや他の言語からクエリを組み立てる場合)。

あなたがそれを行うことができない場合は、私たちが使用できる別のアプローチがあります。

まず、あなたのリレーションシップタイプをLIVES_INに変更します.LIVES_INは、後で簡単にマッチングを行うことができます。

国、州、市でOPTIONAL MATCHを最初に使用し、これらを単一のリストに集めて(データが利用できないヌルノードを削除して)、同じ人物には:コレクション内のすべてのノードに対するLIVES_INの関係があります。すべてのユーザーの代わりに試合より

WITH {country:'Canada', state:'Ontario', city:'Not Available'} as params 
OPTIONAL MATCH (c:Country{name:params.country}) 
OPTIONAL MATCH (s:State{name:params.state}) 
OPTIONAL MATCH (ci:City{name:params.city}) 
WITH FILTER(loc in [c, s, ci] WHERE loc IS NOT null) as locations 
WITH locations, LAST(locations) as place 
MATCH (n:User)-[:LIVES_IN]->(place) 
WHERE ALL(loc in locations WHERE (n)-[:LIVES_IN]->(loc)) 
RETURN n 

その後、WHERE ALL、我々は代わりに(都市、状態、そして国)利用可能な場合、最も狭い場所に住んでいる人々に、ユーザーの私達の潜在的なセットを絞り込む行います。

EDIT - 他のノード/関係にクエリーを拡張

上記のクエリの警告は、(国、州、または都市)存在する少なくとも1つの位置を必要とします。いずれも利用できない場合、クエリは失敗します。この可能性を考慮する必要がある場合は、コメントに私に教えてください。

他のノードと異なる関係でこれを拡張することは可能ですが、アプローチを理解するにはもう少し考えが必要です。複数の型が同じ型に属する場合、型のすべてがdb内で同じラベルのノードによって表される場合に役立ちます。

あなたのスポーツの例では、ほとんどの場合、クエリのスポーツ名のリストを渡すでしょう。いくつかあります:スポーツごとのスポーツノード。

WITH {country:'Canada', state:'Ontario', city:'Not Available', sports:['Hockey', 'Karate']} as params 
WITH params, [(s:Sport)-[*0]-() WHERE s.name in params.sports | s] as sports 
// keep the location section of your query the same 
OPTIONAL MATCH (c:Country{name:params.country}) 
OPTIONAL MATCH (s:State{name:params.state}) 
OPTIONAL MATCH (ci:City{name:params.city}) 
WITH sports, FILTER(loc in [c, s, ci] WHERE loc IS NOT null) as locations 
WITH sports, locations, LAST(locations) as place 
MATCH (n:User)-[:LIVES_IN]->(place) 
WHERE ALL(loc in locations WHERE (n)-[:LIVES_IN]->(loc)) 
// now do additional filtering on sports played 
AND ALL(sport in sports WHERE (n)-[:PLAYS]->(sport)) 
RETURN n 

最も複雑な部分は、2行目(アップのみのNeo4j 3.1で利用可能と)パターンの理解である:よう

修正クエリが見えるかもしれません

[(s:Sport)-[*0]-() WHERE s.name in sports | s] as sports 

それがだろうが(s:Sport)を単独で使用する方が簡単だったため、Cypherはそのパターンをパターンとして認識しないため、0の長さの関係のパターンを使用することでそれをだます必要があります。

これは、スポーツ名のリストパラメータを取得し、関連するスポーツノードのリストを返すためです。

スポーツ用の空リストを渡すと、このパターンの解説は空のリストになり、クエリを続行できます。

あなたのリストをスポーツ名の行に一致させようとすると、あなたのリストを空のリスト上で実行すると行がなくなり、その結果、クエリはそれ以上実行されません。

EDIT - すべてのフィールドは任意です

すべてのフィールドはオプションです。効率の問題があります。

私のクエリでは、一致する可能性のある最小の地理的な場所を使用して、ある場所のユーザーと照合します。これは、次のフィルタリングを無効にするのに役立ちます。このレベルのユーザーは一定時間の操作です。実際にすべてのユーザーとフィルターを調べる必要はないため、場所から関連ユーザーのセットまでの関係に従います。その後のマッチングまたはフィルタリングでは、一致したユーザのセットが引き続き低下し、効率が良い。

ただし、コレクション内に場所がない場合、一致とクエリは失敗します。代わりにOPTIONAL MATCHを使用すると、残りのパターンマッチで再利用するためには役に立たないnullが返されます。

唯一の方法は、すべてのユーザーと一致させることです。ユーザーは最初にユーザーをフィルタリングします。その結果、ユーザーノードの数が増えるにつれて、クエリのパフォーマンスに影響を与え、速度が低下します。すべてのフィールドがオプションで、ユーザーとのマッチを開始する信頼できる場所がない限り、これを回避する方法はありません。

WITH {country:'Canada', state:'Ontario', city:'Not Available', sports:['Hockey', 'Karate']} as params 
WITH params, [(s:Sport)-[*0]-() WHERE s.name in params.sports | s] as sports 
OPTIONAL MATCH (c:Country{name:params.country}) 
OPTIONAL MATCH (s:State{name:params.state}) 
OPTIONAL MATCH (ci:City{name:params.city}) 
WITH sports, FILTER(loc in [c, s, ci] WHERE loc IS NOT null) as locations 
// now start matching using the set of all :Users 
MATCH (n:User) 
WHERE CASE WHEN SIZE(locations) <> 0 THEN 
    ALL(loc in locations WHERE (n)-[:LIVES_IN]->(loc)) 
    ELSE true END 
// now do additional filtering on sports played 
AND CASE WHEN SIZE(sports) <> 0 THEN 
    ANY(sport in sports WHERE (n)-[:PLAYS]->(sport)) 
    ELSE true END 
RETURN n 

EDIT - ANによるALL()関数に、私は何の場所、または渡されていないスポーツが存在しない場合、私は与えたクエリが失敗することを実現し、オプションパラメータ

を支援するcase文(空のリストは偽になります)、コレクションが空でない場合にのみ、CASEステートメントを使用してこれらの評価を実行するために上記のクエリを編集しました。

また、与えられたすべてのスポーツをプレイするユーザーではなく、与えられたスポーツをプレイしているユーザーを返すように、ALL()からANY()に機能を変更しました。

EDIT - プロパティ処理の追加。

我々は18と30歳の間でユーザを取得したい場合は、我々はさらに、フィルタリングを追加することができます

WITH {country:'Canada', state:'Ontario', city:'Not Available', sports:['Hockey', 'Karate'], ageMin:18, ageMax:25} as params 
WITH params, [(s:Sport)-[*0]-() WHERE s.name in params.sports | s] as sports 
OPTIONAL MATCH (c:Country{name:params.country}) 
OPTIONAL MATCH (s:State{name:params.state}) 
OPTIONAL MATCH (ci:City{name:params.city}) 
WITH sports, FILTER(loc in [c, s, ci] WHERE loc IS NOT null) as locations, params.ageMin as ageMin, params.ageMax as ageMax 
// now start matching using the set of all :Users 
MATCH (n:User) 
WHERE CASE WHEN SIZE(locations) <> 0 THEN 
    ALL(loc in locations WHERE (n)-[:LIVES_IN]->(loc)) 
    ELSE true END 
// now do additional filtering on sports played 
AND CASE WHEN ageMin <> 0 THEN 
    n.age >= ageMin 
    ELSE true END 
AND CASE WHEN ageMax <> 0 THEN 
    n.age <= ageMax 
    ELSE true END 
AND CASE WHEN SIZE(sports) <> 0 THEN 
    ANY(sport in sports WHERE (n)-[:PLAYS]->(sport)) 
    ELSE true END 
RETURN n 

EDIT

あなたの元の要件では、有効な地名に渡すか、「未されるだろうということでした無効な場所名を処理できるようにするためにできることを見てみましょう。

私たちを助けるために、:Invalidノードを作成して、それ以上の一致を避けるために場所を「スパイク」するようにしましょう。

CREATE (:Invalid) 

今、私たちは、上のオプションMATCHをやる:無効なノードと場所でそれを含めるが、それは場合にのみ、街の一つ、国、照合されますので、我々はそれに述語を追加しますまたは状態のOPTIONAL MATCHESは失敗しますが、関連するパラメータは 'Not Applicable'ではありません。

状態の 'Alberta'にOPTIONAL MATCHを実行しようとしたが、ノードが存在しない場合、状態ノードの変数はNULLになり、関連付けられたパラメータは 'Not Applicable ':無効なノードが場所リストに表示され、人物が一致しないようにします(場所リストが空でない場合、リストのすべての要素にLIVES_INの関係があります)。

WITH {country:'Canada', state:'Ontario', city:'Not Available', sports:['Hockey', 'Karate'], ageMin:18, ageMax:25} as params 
WITH params, [(s:Sport)-[*0]-() WHERE s.name in params.sports | s] as sports 
OPTIONAL MATCH (c:Country{name:params.country}) 
OPTIONAL MATCH (s:State{name:params.state}) 
OPTIONAL MATCH (ci:City{name:params.city}) 
OPTIONAL MATCH (inv:Invalid) 
WHERE (c is null AND params.country <> 'Not Available') OR 
     (s is null AND params.state <> 'Not Available') OR 
     (ci is null AND params.city <> 'Not Available') 
WITH sports, FILTER(loc in [c, s, ci, inv] WHERE loc IS NOT null) as locations, params.ageMin as ageMin, params.ageMax as ageMax 
// now start matching using the set of all :Users 
MATCH (n:User) 
WHERE CASE WHEN SIZE(locations) <> 0 THEN 
    ALL(loc in locations WHERE (n)-[:LIVES_IN]->(loc)) 
    ELSE true END 
// now do additional filtering on sports played 
AND CASE WHEN ageMin <> 0 THEN 
    n.age >= ageMin 
    ELSE true END 
AND CASE WHEN ageMax <> 0 THEN 
    n.age <= ageMax 
    ELSE true END 
AND CASE WHEN SIZE(sports) <> 0 THEN 
    ANY(sport in sports WHERE (n)-[:PLAYS]->(sport)) 
    ELSE true END 
RETURN n 
+0

私は質問にそれを入れておくべきだった。私はすでにそれを試みたが、それは正しい結果を与えていない。 OPTIONAL MATCHはすべての国とすべての州などの結果を返します。 – jas

+0

オプションのクエリを追加しました。私はその質問に挑戦しました。どのように私がそれを書いたかに何か問題があるかどうかわからない – jas

+0

あなたのために働くべきクエリーで編集。 – InverseFalcon

関連する問題