で可能であるかどうかわから国、州、および都市の代わりに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
私は質問にそれを入れておくべきだった。私はすでにそれを試みたが、それは正しい結果を与えていない。 OPTIONAL MATCHはすべての国とすべての州などの結果を返します。 – jas
オプションのクエリを追加しました。私はその質問に挑戦しました。どのように私がそれを書いたかに何か問題があるかどうかわからない – jas
あなたのために働くべきクエリーで編集。 – InverseFalcon