2

Neo4j で「友達の友達」タイプの MATCH を実行しています。私をうんざりさせているのは、すべての関係を日付で制限しようとすることだけです。

基本的なグラフは次のようになります。

ここに画像の説明を入力

グラフの「実際の」バージョンには、10 人の第 1 度の友人と 3385 人の第 2 度の友人がいます。

上の画像の各エッジに日付プロパティを配置しませんでしたが、実際にそうです。どの日付にも順序はありません。

一般的な考え方は非常に単純です。あらかじめ決められた最大日付よりも古い日付プロパティを持つ関係は無視するようにします。

少しトリッキーな部分は、最初のリレーションシップ内で最大日付の制約に違反した場合 (上の画像のノードから外れている 3 つのエッジの 1 つなど)、そのエッジは半分に分割され、そのパスを他のトラバーサルは行わないことです。発生できるはずです。(たとえば、葉ノードは必要ありません)。

私はこれを書きました:

MATCH
(n)-[f1:FRIEND]-()-[f2:FRIEND]-(m)
WITH n, m,split('1962-1-1', '-') AS maxdate
WHERE n.person_id='180'
AND(
(
toInt(maxdate[0]) > toInt(split(f1.date, '-')[0])
)   
OR
(
toInt(maxdate[0]) = toInt(split(f1.date, '-')[0])
 AND
toInt(maxdate[1]) >= toInt(split(f1.date, '-')[1])
))
AND(
(
toInt(maxdate[0]) > toInt(split(f2.date, '-')[0])
)   
OR
(
toInt(maxdate[0]) = toInt(split(f2.date, '-')[0])
 AND
toInt(maxdate[1]) >= toInt(split(f2.date, '-')[1])
))
RETURN m;

このコード ブロックは約 20 分間実行され、最終的には私が目指していたものに近い結果になったようです。ブラウザでの表示は次のとおりです。

ここに画像の説明を入力

(ノード数は 350)

最初に、これが明らかにひどく書かれたコードであることを認めます (美学とパフォーマンスの両方の点で)。2 つ目は、境界に関連付けられていないノードがあることに気付きました。

私が考えているのは、1親等の関係の日付条件が失敗した場合ですが、2親等の関係では失敗したため、含まれたくない「友人の友人」になってしまいました。

1 次エッジが無効になったときにこれらの独立したノードを削除するように日付条件を変更するにはどうすればよいですか?

誰かが何か洞察を持っているなら、私はそれを大いに感謝します. (あまりどろどろにするつもりはありませんが、SO コミュニティのおかげで、私はすでに比較的かなり早くここまで来ました。そのため、感謝しています。)

4

1 に答える 1

4

そもそもそれほど長く実行するべきではありません。主な理由は、ノードにラベルとインデックスがないためです。

それらを最初に追加します:

CREATE CONSTRAINT ON (p:Person) ASSERT p.person_id is unique;
MATCH (n) where exists(n.person_id) SET n:Person;

とにかく時間があればyyyy-mm-dd(少なくともそうだといいのですが)それらを直接比較できます:(別名2桁で01)つまり'2012-01-10' > '2011-08-31'

WITH '1962-01-01' AS maxdate
MATCH (n:Person)-[f1:FRIEND]-()-[f2:FRIEND]-(m:Person)
WHERE n.person_id='180' AND f1.date < maxdate and f2.date < maxdate
RETURN m;

短い形式を使用することもできます:(n:Person {person_id:'180'})

パス内のリレーションシップに関する一般的な式が必要な場合は、可変長relsパス パターン内で変数 (コレクション) を使用します。

WITH '1962-01-01' AS maxdate
MATCH (n:Person {person_id:'180'})-[rels:FRIEND*2]-(m:Person)
WHERE ALL(r in rels WHERE r.date < maxdate)
RETURN m;

あなたも使うことができますrels(path)

WITH '1962-01-01' AS maxdate
MATCH path = (n:Person {person_id:'180'})-[:FRIEND*2]-(m:Person)
WHERE ALL(r in rels(path) WHERE r.date < maxdate)
RETURN m;

または、パスの関係が相互に関連している場合:

WITH '1962-01-01' AS maxdate
MATCH (n:Person  {person_id:'180'})-[rels:FRIEND*2]-(m:Person)
WHERE ALL(idx in range(0, size(rels)-2) WHERE (rels[idx]).date < maxdate AND (rels[idx]).date < (rels[idx+1]).date)
RETURN m;
于 2016-05-21T10:53:25.147 に答える