gds(3) 유사성 알고리즘 체험기 - sfjun/neo4j GitHub Wiki
유사성 알고리즘
-생산 품질 노드 유사성
-베타 K- 최근 접 이웃
-알파 근사치 인접 이웃 코사인 유사성 유클리드 유사성 Jaccard 유사성 중복 유사성 피어슨 유사성
노드 유사성
알고리즘은 Jaccard 유사성 점수를 기반
노드 유사성 알고리즘은 연결된 노드를 기반으로 노드 집합을 비교합니다. 두 노드가 동일한 이웃을 많이 공유하는 경우 유사한 것으로 간주됩니다. 노드 유사성은 Jaccard 유사성 점수라고도하는 Jaccard 지표를 기반으로 쌍별 유사성을 계산합니다.
예)
CREATE (alice:Person {name: 'Alice'}), (bob:Person {name: 'Bob'}), (carol:Person {name: 'Carol'}), (dave:Person {name: 'Dave'}), (eve:Person {name: 'Eve'}), (guitar:Instrument {name: 'Guitar'}), (synth:Instrument {name: 'Synthesizer'}), (bongos:Instrument {name: 'Bongos'}), (trumpet:Instrument {name: 'Trumpet'}),
(alice)-[:LIKES]->(guitar), (alice)-[:LIKES]->(synth), (alice)-[:LIKES {strength: 0.5}]->(bongos), (bob)-[:LIKES]->(guitar), (bob)-[:LIKES]->(synth), (carol)-[:LIKES]->(bongos), (dave)-[:LIKES]->(guitar), (dave)-[:LIKES]->(synth), (dave)-[:LIKES]->(bongos);
Added 9 labels, created 9 nodes, set 10 properties, created 9 relationships, completed after 25 ms.
CALL gds.graph.create( 'myGraph', ['Person', 'Instrument'], { LIKES: { type: 'LIKES', properties: { strength: { property: 'strength', defaultValue: 1.0 } } } } );
nodeProjection relationshipProjection graphName nodeCount relationshipCount createMillis { "Instrument": { "properties": {
},
"label": "Instrument" }, "Person": { "properties": {
},
"label": "Person" } } { "LIKES": { "orientation": "NATURAL", "aggregation": "DEFAULT", "type": "LIKES", "properties": { "strength": { "property": "strength", "aggregation": "DEFAULT", "defaultValue": 1.0 } } } } "myGraph" 9 9 14
3.1. 메모리 추정
CALL gds.nodeSimilarity.write.estimate('myGraph', { writeRelationshipType: 'SIMILAR', writeProperty: 'score' }) YIELD nodeCount, relationshipCount, bytesMin, bytesMax, requiredMemory
nodeCount relationshipCount bytesMin bytesMax requiredMemory
9 9 2592 2808 "[2592 Bytes ... 2808 Bytes]"
3.2. 흐름
CALL gds.nodeSimilarity.stream('myGraph') YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY similarity DESCENDING, Person1, Person2
Person1 Person2 similarity "Alice" "Dave" 1.0 "Dave" "Alice" 1.0 "Alice" "Bob" 0.6666666666666666 "Bob" "Alice" 0.6666666666666666 "Bob" "Dave" 0.6666666666666666 "Dave" "Bob" 0.6666666666666666 "Alice" "Carol" 0.3333333333333333 "Carol" "Alice" 0.3333333333333333 "Carol" "Dave" 0.3333333333333333 "Dave" "Carol" 0.3333333333333333
3.3. 통계
CALL gds.nodeSimilarity.stats('myGraph') YIELD nodesCompared, similarityPairs
nodesCompared similarityPairs 4 10
3.4. 돌연변이
CALL gds.nodeSimilarity.mutate('myGraph', { mutateRelationshipType: 'SIMILAR', mutateProperty: 'score' }) YIELD nodesCompared, relationshipsWritten
nodesCompared relationshipsWritten 4 10
3.5. 쓰다
CALL gds.nodeSimilarity.write('myGraph', { writeRelationshipType: 'SIMILAR', writeProperty: 'score' }) YIELD nodesCompared, relationshipsWritten
nodesCompared relationshipsWritten 4 12
3.6. 결과 제한
3.6.1. topK 및 bottomK
TopK 및 bottomK는 노드 당 계산되는 점수 수에 대한 제한입니다. topK의 경우 노드 당 K 개의 가장 큰 유사성 점수가 반환됩니다. bottomK의 경우 노드 당 K 개의 최소 유사성 점수가 반환됩니다. TopK 및 bottomK는 0이 될 수 없으며 함께 사용할 수 있으며 기본값은 10입니다. 둘 다 지정하지 않으면 topK가 사용됩니다.
CALL gds.nodeSimilarity.stream('myGraph', { topK: 1 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY Person1
Person1 Person2 similarity "Alice" "Bob" 0.42857142857142855 "Bob" "Alice" 0.42857142857142855 "Carol" "Bob" 0.4 "Dave" "Alice" 0.2
CALL gds.nodeSimilarity.stream('myGraph', { bottomK: 1 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY Person1
Person1 Person2 similarity "Alice" "Dave" 0.2 "Bob" "Dave" 0.1111111111111111 "Carol" "Dave" 0.125 "Dave" "Bob" 0.1111111111111111
3.6.2. topN 및 bottomN TopN 및 bottomN은 모든 노드에서 유사성 점수의 수를 제한합니다. 이는 노드 당 결과에 대한 topK 또는 bottomK 한계와 더불어 총 결과 세트에 대한 한계입니다. topN의 경우 N 개의 가장 큰 유사성 점수가 반환됩니다. bottomN의 경우 N 개의 최소 유사성 점수가 반환됩니다. 값 0은 전역 제한이 적용되지 않고 topK 또는 bottomK의 모든 결과가 반환됨을 의미합니다.
CALL gds.nodeSimilarity.stream('myGraph', { topK: 1, topN: 3 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY similarity DESC, Person1, Person2
Person1 Person2 similarity
"Alice" "Bob" 0.42857142857142855 "Bob" "Alice" 0.42857142857142855 "Carol" "Bob" 0.4
3.7. 정도 컷오프 및 유사성 컷오프 차수 컷오프는 노드가 비교에서 고려되는 노드 차수의 하한입니다. 이 값은 1보다 작을 수 없습니다.
CALL gds.nodeSimilarity.stream('myGraph', { degreeCutoff: 3 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY Person1
Person1 Person2 similarity "Alice" "Bob" 0.42857142857142855 "Alice" "Carol" 0.2857142857142857 "Alice" "Dave" 0.2 "Bob" "Alice" 0.42857142857142855 "Bob" "Carol" 0.4 "Bob" "Dave" 0.1111111111111111 "Carol" "Bob" 0.4
유사성 컷오프는 결과에 표시되는 유사성 점수의 하한입니다. 1E-42유사성 점수가 0 인 결과를 제외하기 위한 기본값은 매우 작습니다 ( ).
CALL gds.nodeSimilarity.stream('myGraph', { similarityCutoff: 0.5 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY Person1
(no changes, no records)
3.8. 가중 Jaccard 유사성 관계 속성을 사용하여 특정 관계로 인한 유사성을 수정할 수 있습니다. 예를 들어 관계 값 2는 jaccard 유사성을 계산하는 동안 해당 관계를 두 번 계산하는 것과 같습니다.
CALL gds.nodeSimilarity.stream('myGraph', { relationshipWeightProperty: 'strength', similarityCutoff: 0.5 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY Person1
Failed to invoke procedure gds.nodeSimilarity.stream: Caused by: java.lang.UnsupportedOperationException
K- 최근접 이웃, KNN (K-Nearest Neighbors)
모든 노드 쌍에 대한 거리 값을 계산하고 각 노드와 k 개의 가장 가까운 이웃 사이에 새로운 관계를 생성 실제로 노드 간의 기존 관계는 무시됩니다. 각 노드와 k 개의 최근 접 이웃간에 새로운 관계가 생성됩니다.
예)
CREATE (alice:Person {name: 'Alice', age: 24}) CREATE (bob:Person {name: 'Bob', age: 73}) CREATE (carol:Person {name: 'Carol', age: 24}) CREATE (dave:Person {name: 'Dave', age: 48}) CREATE (eve:Person {name: 'Eve', age: 67});
Added 5 labels, created 5 nodes, set 10 properties, completed after 14 ms.
CALL gds.graph.create( 'myGraph', { Person: { label: 'Person', properties: 'age' } }, '*' );
nodeProjection relationshipProjection graphName nodeCount relationshipCount createMillis
{ "Person": { "properties": { "age": { "property": "age", "defaultValue": null } }, "label": "Person" } } { "ALL": { "orientation": "NATURAL", "aggregation": "DEFAULT", "type": "*", "properties": { } } } "myGraph" 5 0 11
3.1. 메모리 추정
CALL gds.beta.knn.write.estimate('myGraph', { nodeWeightProperty: 'age', writeRelationshipType: 'SIMILAR', writeProperty: 'score', topK: 1 }) YIELD nodeCount, bytesMin, bytesMax, requiredMemory
nodeCount bytesMin bytesMax requiredMemory 5 1224 2184 "[1224 Bytes ... 2184 Bytes]"
3.2. 흐름
CALL gds.beta.knn.stream('myGraph', { topK: 1, nodeWeightProperty: 'age', // The following parameters are set to produce a deterministic result randomSeed: 42, concurrency: 1, sampleRate: 1.0, deltaThreshold: 0.0 }) YIELD node1, node2, similarity RETURN gds.util.asNode(node1).name AS Person1, gds.util.asNode(node2).name AS Person2, similarity ORDER BY similarity DESCENDING, Person1, Person2
Person1 Person2 similarity "Alice" "Carol" 1.0 "Carol" "Alice" 1.0 "Bob" "Eve" 0.14285714285714285 "Eve" "Bob" 0.14285714285714285 "Dave" "Eve" 0.05
3.3. 통계
CALL gds.beta.knn.stats('myGraph', {topK: 1, randomSeed: 42, nodeWeightProperty: 'age'}) YIELD nodesCompared, similarityPairs
nodesCompared similarityPairs 5 5
3.4. 돌연변이
CALL gds.beta.knn.mutate('myGraph', { mutateRelationshipType: 'SIMILAR', mutateProperty: 'score', topK: 1, randomSeed: 42, nodeWeightProperty: 'age' }) YIELD nodesCompared, relationshipsWritten
nodesCompared relationshipsWritten 5 5
3.5. 쓰다
CALL gds.beta.knn.write('myGraph', { writeRelationshipType: 'SIMILAR', writeProperty: 'score', topK: 1, randomSeed: 42, nodeWeightProperty: 'age' }) YIELD nodesCompared, relationshipsWritten
nodesCompared relationshipsWritten 5 5
MATCH p = (a)-[r]-(b) RETURN a.name, type(r),r, b.name
??????????????????????????????????????????????????????????? │"a.name"│"type(r)"│"r" │"b.name"│ ??????????????????????????????????????????????????????????? │"Alice" │"SIMILAR"│{"score":1.0} │"Carol" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Alice" │"SIMILAR"│{"score":1.0} │"Carol" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Bob" │"SIMILAR"│{"score":0.14285714285714285}│"Eve" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Bob" │"SIMILAR"│{"score":0.14285714285714285}│"Eve" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Carol" │"SIMILAR"│{"score":1.0} │"Alice" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Carol" │"SIMILAR"│{"score":1.0} │"Alice" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Dave" │"SIMILAR"│{"score":0.05} │"Eve" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Eve" │"SIMILAR"│{"score":0.05} │"Dave" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Eve" │"SIMILAR"│{"score":0.14285714285714285}│"Bob" │ ├────────┼─────────┼─────────────────────────────┼────────┤ │"Eve" │"SIMILAR"│{"score":0.14285714285714285}│"Bob" │ └────────┴─────────┴─────────────────────────────┴────────┘
-->SIMILAR 관계생성, score 속성 생성
Jaccard 유사성
세트 간의 유사성을 측정합니다. 두 세트의 합집합 크기로 나눈 교차점 크기로 정의
RETURN gds.alpha.similarity.jaccard([1,2,3], [1,2,4,5]) AS similarity
similarity 0.4
#배열의 길이가 달라도 가능...consine과 jaccard의 차이???
CREATE (french:Cuisine {name:'French'}), (italian:Cuisine {name:'Italian'}), (indian:Cuisine {name:'Indian'}), (lebanese:Cuisine {name:'Lebanese'}), (portuguese:Cuisine {name:'Portuguese'}),
(zhen:Person {name: 'Zhen'}), (praveena:Person {name: 'Praveena'}), (michael:Person {name: 'Michael'}), (arya:Person {name: 'Arya'}), (karin:Person {name: 'Karin'}),
(praveena)-[:LIKES]->(indian), (praveena)-[:LIKES]->(portuguese),
(zhen)-[:LIKES]->(french), (zhen)-[:LIKES]->(indian),
(michael)-[:LIKES]->(french), (michael)-[:LIKES]->(italian), (michael)-[:LIKES]->(indian),
(arya)-[:LIKES]->(lebanese), (arya)-[:LIKES]->(italian), (arya)-[:LIKES]->(portuguese),
(karin)-[:LIKES]->(lebanese), (karin)-[:LIKES]->(italian)
Added 10 labels, created 10 nodes, set 10 properties, created 12 relationships, completed after 21 ms
MATCH (p1:Person {name: 'Karin'})-[:LIKES]->(cuisine1) WITH p1, collect(id(cuisine1)) AS p1Cuisine MATCH (p2:Person {name: "Arya"})-[:LIKES]->(cuisine2) WITH p1, p1Cuisine, p2, collect(id(cuisine2)) AS p2Cuisine RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.jaccard(p1Cuisine, p2Cuisine) AS similarity
from to similarity "Karin" "Arya" 0.6666666666666666
MATCH (p1:Person {name: 'Karin'})-[:LIKES]->(cuisine1) WITH p1, collect(id(cuisine1)) AS p1Cuisine MATCH (p2:Person)-[:LIKES]->(cuisine2) WHERE p1 <> p2 WITH p1, p1Cuisine, p2, collect(id(cuisine2)) AS p2Cuisine RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.jaccard(p1Cuisine, p2Cuisine) AS similarity ORDER BY to, similarity DESC
from to similarity "Karin" "Arya" 0.6666666666666666 "Karin" "Michael" 0.25 "Karin" "Praveena" 0.0 "Karin" "Zhen" 0.0
코사인 유사성
n 차원 공간에서 두 개의 n 차원 벡터 사이 각도의 코사인입니다 . 두 벡터의 내적을 두 벡터의 길이 (또는 크기)의 곱으로 나눈 값입니다.
라이브러리에는 데이터 세트 간의 유사성을 계산하는 프로시저와 함수가 모두 포함되어 있습니다. 이 함수는 적은 수의 집합 간의 유사성을 계산할 때 가장 잘 사용됩니다. 프로시저는 계산을 병렬화하므로 더 큰 데이터 세트의 유사성을 계산하는 데 더 적합합니다.
RETURN gds.alpha.similarity.cosine([3,8,7,5,2,9], [10,8,6,6,4,5]) AS similarity
similarity 0.863893562679159
->배열의 길이가 같을때만 사용, 다르면 짧은길에 맞춰서 진행
CREATE (french:Cuisine {name:'French'}) CREATE (italian:Cuisine {name:'Italian'}) CREATE (indian:Cuisine {name:'Indian'}) CREATE (lebanese:Cuisine {name:'Lebanese'}) CREATE (portuguese:Cuisine {name:'Portuguese'}) CREATE (british:Cuisine {name:'British'}) CREATE (mauritian:Cuisine {name:'Mauritian'})
CREATE (zhen:Person {name: "Zhen"}) CREATE (praveena:Person {name: "Praveena"}) CREATE (michael:Person {name: "Michael"}) CREATE (arya:Person {name: "Arya"}) CREATE (karin:Person {name: "Karin"})
CREATE (praveena)-[:LIKES {score: 9}]->(indian) CREATE (praveena)-[:LIKES {score: 7}]->(portuguese) CREATE (praveena)-[:LIKES {score: 8}]->(british) CREATE (praveena)-[:LIKES {score: 1}]->(mauritian)
CREATE (zhen)-[:LIKES {score: 10}]->(french) CREATE (zhen)-[:LIKES {score: 6}]->(indian) CREATE (zhen)-[:LIKES {score: 2}]->(british)
CREATE (michael)-[:LIKES {score: 8}]->(french) CREATE (michael)-[:LIKES {score: 7}]->(italian) CREATE (michael)-[:LIKES {score: 9}]->(indian) CREATE (michael)-[:LIKES {score: 3}]->(portuguese)
CREATE (arya)-[:LIKES {score: 10}]->(lebanese) CREATE (arya)-[:LIKES {score: 10}]->(italian) CREATE (arya)-[:LIKES {score: 7}]->(portuguese) CREATE (arya)-[:LIKES {score: 9}]->(mauritian)
CREATE (karin)-[:LIKES {score: 9}]->(lebanese) CREATE (karin)-[:LIKES {score: 7}]->(italian) CREATE (karin)-[:LIKES {score: 10}]->(portuguese)
Added 12 labels, created 12 nodes, set 30 properties, created 18 relationships, completed after 39 ms.
MATCH (p1:Person {name: 'Michael'})-[likes1:LIKES]->(cuisine) MATCH (p2:Person {name: "Arya"})-[likes2:LIKES]->(cuisine) RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.cosine(collect(likes1.score), collect(likes2.score)) AS similarity
from to similarity "Michael" "Arya" 0.9788908326303921
MATCH (p1:Person {name: 'Michael'})-[likes1:LIKES]->(cuisine) MATCH (p2:Person)-[likes2:LIKES]->(cuisine) WHERE p2 <> p1 RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.cosine(collect(likes1.score), collect(likes2.score)) AS similarity ORDER BY similarity DESC
from to similarity "Michael" "Arya" 0.9788908326303921 "Michael" "Zhen" 0.9542262139256075 "Michael" "Praveena" 0.9429903335828894 "Michael" "Karin" 0.8498063272285821
- 코사인 유사성 알고리즘 절차 예제 코사인 유사성 프로시저는 모든 항목 쌍 간의 유사성을 계산합니다. 이것은 대칭 알고리즘입니다. 즉, 항목 A와 항목 B의 유사성을 계산한 결과는 항목 B와 항목 A의 유사성을 계산 한 것과 같습니다. 따라서 각 노드 쌍에 대한 점수를 한번 계산할 수 있습니다. 우리는 항목의 유사성을 스스로 계산하지 않습니다.
코사인 유사성은 NULL이 아닌 차원에 대해서만 계산됩니다. 절차는 모든 항목에 대해 동일한 길이 목록을받을 것으로 예상합니다. 그렇지 않으면 긴 목록이 가장 짧은 목록의 길이로 잘립니다.
5.1. 흐름
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.cosine.stream({data: data}) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Praveena" "Karin" 1.0 "Karin" "Praveena" 1.0 "Michael" "Arya" 0.9788908326303921 "Arya" "Michael" 0.9788908326303921 "Arya" "Karin" 0.9610904115204073 "Karin" "Arya" 0.9610904115204073 "Zhen" "Michael" 0.9542262139256075 "Michael" "Zhen" 0.9542262139256075 "Praveena" "Michael" 0.9429903335828895 "Michael" "Praveena" 0.9429903335828895 "Zhen" "Praveena" 0.9191450300180579 "Praveena" "Zhen" 0.9191450300180579 "Karin" "Michael" 0.8498063272285821 "Arya" "Praveena" 0.7194014606174091 "Zhen" "Arya" 0.0
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.cosine.stream({ data: data, similarityCutoff: 0.0 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Praveena" "Karin" 1.0 "Karin" "Praveena" 1.0 "Michael" "Arya" 0.9788908326303921 "Arya" "Michael" 0.9788908326303921 "Arya" "Karin" 0.9610904115204073 "Karin" "Arya" 0.9610904115204073 "Zhen" "Michael" 0.9542262139256075 "Michael" "Zhen" 0.9542262139256075 "Praveena" "Michael" 0.9429903335828895 "Michael" "Praveena" 0.9429903335828895 "Zhen" "Praveena" 0.9191450300180579 "Praveena" "Zhen" 0.9191450300180579 "Karin" "Michael" 0.8498063272285821 "Arya" "Praveena" 0.7194014606174091
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.cosine.stream({ data: data, similarityCutoff: 0.0, topK: 1 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY from
from to similarity "Arya" "Michael" 0.9788908326303921 "Karin" "Praveena" 1.0 "Michael" "Arya" 0.9788908326303921 "Praveena" "Karin" 1.0 "Zhen" "Michael" 0.9542262139256075
-> k-Nearest Neighbors 유형 쿼리를 구현하는 경우 대신 k주어진 사용자에 대해 가장 유사한 사용자 를 찾고 싶을 수 있습니다 . topK매개 변수 를 전달하면 됩니다.
5.2. 쓰다
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.cosine.write({ data: data, topK: 1, similarityCutoff: 0.1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
nodes similarityPairs writeRelationshipType writeProperty min max mean p95 5 5 "SIMILAR" "score" 0.9542236328125 1.0000038146972656 0.9824020385742187 1.0000038146972656
다음은 Praveena와 가장 유사한 사용자를 찾고 Praveena가 (아직!) 좋아하지 않는 좋아하는 요리를 반환합니다.
MATCH (p:Person {name: "Praveena"})-[:SIMILAR]->(other), (other)-[:LIKES]->(cuisine) WHERE not((p)-[:LIKES]->(cuisine)) RETURN cuisine.name AS cuisine
cuisine "Italian" "Lebanese"
5.3. 통계
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.cosine.stats({ data: data, topK: 1, similarityCutoff: 0.1 }) YIELD nodes, similarityPairs, min, max, mean, p95 RETURN nodes, similarityPairs, min, max, mean, p95
nodes similarityPairs min max mean p95 5 5 0.9542236328125 1.0000038146972656 0.9824020385742187 1.0000038146972656
- 소스 및 대상 ID 지정
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), name: p.name, weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS personCuisines WITH personCuisines, [value in personCuisines WHERE value.name IN ["Praveena", "Arya"] | value.item ] AS sourceIds CALL gds.alpha.similarity.cosine.stream({ data: personCuisines, sourceIds: sourceIds, topK: 1 }) YIELD item1, item2, similarity WITH gds.util.asNode(item1) AS from, gds.util.asNode(item2) AS to, similarity RETURN from.name AS from, to.name AS to, similarity ORDER BY similarity DESC
from to similarity "Praveena" "Karin" 1.0 "Arya" "Michael" 0.9788908326303921
- 값 건너 뛰기
샘플생성)
CREATE (french:Cuisine {name:'French'}) SET french.embedding = [0.71, 0.33, 0.81, 0.52, 0.41] CREATE (italian:Cuisine {name:'Italian'}) SET italian.embedding = [0.31, 0.72, 0.58, 0.67, 0.31] CREATE (indian:Cuisine {name:'Indian'}) SET indian.embedding = [0.43, 0.26, 0.98, 0.51, 0.76] CREATE (lebanese:Cuisine {name:'Lebanese'}) SET lebanese.embedding = [0.12, 0.23, 0.35, 0.31, 0.39] CREATE (portuguese:Cuisine {name:'Portuguese'}) SET portuguese.embedding = [0.47, 0.98, 0.81, 0.72, 0.89] CREATE (british:Cuisine {name:'British'}) SET british.embedding = [0.94, 0.12, 0.23, 0.4, 0.71] CREATE (mauritian:Cuisine {name:'Mauritian'}) SET mauritian.embedding = [0.31, 0.56, 0.98, 0.21, 0.62]
Added 7 labels, created 7 nodes, set 14 properties, completed after 110 ms.
MATCH (c:Cuisine) WITH {item:id(c), weights: c.embedding} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.cosine.stream({ data: data, skipValue: null }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Lebanese" "Portuguese" 0.9671144333535775 "Portuguese" "Lebanese" 0.9671144333535775 "Lebanese" "Indian" 0.9590440861639105 "Indian" "Lebanese" 0.9590440861639105 "Portuguese" "Italian" 0.9582444106965535 "Italian" "Portuguese" 0.9582444106965535 "Mauritian" "Indian" 0.9464344561993276 "Indian" "Mauritian" 0.9464344561993276 "French" "Indian" 0.9414524820541921 "Indian" "French" 0.9414524820541921 "Portuguese" "Mauritian" 0.92092461331529 "Mauritian" "Portuguese" 0.92092461331529 "Lebanese" "Mauritian" 0.9192477665074964 "Mauritian" "Lebanese" 0.9192477665074964 "Italian" "Lebanese" 0.9072862556290799 "French" "Mauritian" 0.8913504022120792 "French" "Lebanese" 0.8853775767967607 "Italian" "French" 0.8778358577197801 "British" "French" 0.8384644973081824 "British" "Indian" 0.7717276859027898 "British" "Lebanese" 0.7393113934601527
- 사이퍼 투영
WITH 'MATCH (person:Person)-[likes:LIKES]->(c) RETURN id(person) AS item, id(c) AS category, likes.score AS weight' AS query CALL gds.alpha.similarity.cosine.write({ data: query, graph: 'cypher', topK: 1, similarityCutoff: 0.1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
피어슨 유사성
두 n 차원 벡터 의 공분산을 표준 편차의 곱으로 나눈 값입니다.
Pearson Similarity 알고리즘을 사용하여 두 가지 간의 유사성을 알아낼 수 있습니다. 그런 다음 계산 된 유사성을 추천 쿼리의 일부로 사용할 수 있습니다. 예를 들어, 귀하가 본 다른 영화와 유사한 등급을 부여한 사용자의 선호도를 기반으로 영화 추천을받을 수 있습니다.
Pearson 유사성 함수는 두 숫자 목록의 유사성을 계산합니다.
RETURN gds.alpha.similarity.pearson([5,8,7,5,4,9], [7,8,6,6,4,5]) AS similarity
similarity 0.28767798089123053
예)
MERGE (home_alone:Movie {name:'Home Alone'}) MERGE (matrix:Movie {name:'The Matrix'}) MERGE (good_men:Movie {name:'A Few Good Men'}) MERGE (top_gun:Movie {name:'Top Gun'}) MERGE (jerry:Movie {name:'Jerry Maguire'}) MERGE (gruffalo:Movie {name:'The Gruffalo'})
MERGE (zhen:Person {name: 'Zhen'}) MERGE (praveena:Person {name: 'Praveena'}) MERGE (michael:Person {name: 'Michael'}) MERGE (arya:Person {name: 'Arya'}) MERGE (karin:Person {name: 'Karin'})
MERGE (zhen)-[:RATED {score: 2}]->(home_alone) MERGE (zhen)-[:RATED {score: 2}]->(good_men) MERGE (zhen)-[:RATED {score: 3}]->(matrix) MERGE (zhen)-[:RATED {score: 6}]->(jerry)
MERGE (praveena)-[:RATED {score: 6}]->(home_alone) MERGE (praveena)-[:RATED {score: 7}]->(good_men) MERGE (praveena)-[:RATED {score: 8}]->(matrix) MERGE (praveena)-[:RATED {score: 9}]->(jerry)
MERGE (michael)-[:RATED {score: 7}]->(home_alone) MERGE (michael)-[:RATED {score: 9}]->(good_men) MERGE (michael)-[:RATED {score: 3}]->(jerry) MERGE (michael)-[:RATED {score: 4}]->(top_gun)
MERGE (arya)-[:RATED {score: 8}]->(top_gun) MERGE (arya)-[:RATED {score: 1}]->(matrix) MERGE (arya)-[:RATED {score: 10}]->(jerry) MERGE (arya)-[:RATED {score: 10}]->(gruffalo)
MERGE (karin)-[:RATED {score: 9}]->(top_gun) MERGE (karin)-[:RATED {score: 7}]->(matrix) MERGE (karin)-[:RATED {score: 7}]->(home_alone) MERGE (karin)-[:RATED {score: 9}]->(gruffalo)
Added 11 labels, created 11 nodes, set 31 properties, created 20 relationships, completed after 1533 ms.
다음은 Arya와 Karin의 Pearson 유사성을 반환합니다.
MATCH (p1:Person {name: 'Arya'})-[rated:RATED]->(movie) WITH p1, gds.alpha.similarity.asVector(movie, rated.score) AS p1Vector MATCH (p2:Person {name: 'Karin'})-[rated:RATED]->(movie) WITH p1, p2, p1Vector, gds.alpha.similarity.asVector(movie, rated.score) AS p2Vector RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.pearson(p1Vector, p2Vector, {vectorType: "maps"}) AS similarity
from to similarity "Arya" "Karin" 0.8194651785206903
-> 이 예에서는 vectorType: "maps"추가 매개 변수로 전달하고 gds.alpha.similarity.asVector함수를 사용하여 각 영화와 해당 등급을 포함하는지도 벡터를 구성합니다. 이는 Pearson 유사성 알고리즘이 우리가 비교하는 사용자와 공통된 영화뿐만 아니라 사용자가 리뷰 한 모든 영화 의 평균을 계산해야하기 때문입니다. 따라서 우리는 두 사람이 모두 검토 한 영화 등급 컬렉션을 전달할 수 없습니다.
- Pearson 유사성 알고리즘 절차 샘플
Pearson 유사성은 NULL이 아닌 차원에 대해서만 계산됩니다. 절차는 모든 항목에 대해 동일한 길이 목록을받을 것으로 예상합니다. 그렇지 않으면 긴 목록이 가장 짧은 목록의 길이로 잘립니다.
예)
MERGE (home_alone:Movie {name:'Home Alone'}) MERGE (matrix:Movie {name:'The Matrix'}) MERGE (good_men:Movie {name:'A Few Good Men'}) MERGE (top_gun:Movie {name:'Top Gun'}) MERGE (jerry:Movie {name:'Jerry Maguire'}) MERGE (gruffalo:Movie {name:'The Gruffalo'})
MERGE (zhen:Person {name: 'Zhen'}) MERGE (praveena:Person {name: 'Praveena'}) MERGE (michael:Person {name: 'Michael'}) MERGE (arya:Person {name: 'Arya'}) MERGE (karin:Person {name: 'Karin'})
MERGE (zhen)-[:RATED {score: 2}]->(home_alone) MERGE (zhen)-[:RATED {score: 2}]->(good_men) MERGE (zhen)-[:RATED {score: 3}]->(matrix) MERGE (zhen)-[:RATED {score: 6}]->(jerry)
MERGE (praveena)-[:RATED {score: 6}]->(home_alone) MERGE (praveena)-[:RATED {score: 7}]->(good_men) MERGE (praveena)-[:RATED {score: 8}]->(matrix) MERGE (praveena)-[:RATED {score: 9}]->(jerry)
MERGE (michael)-[:RATED {score: 7}]->(home_alone) MERGE (michael)-[:RATED {score: 9}]->(good_men) MERGE (michael)-[:RATED {score: 3}]->(jerry) MERGE (michael)-[:RATED {score: 4}]->(top_gun)
MERGE (arya)-[:RATED {score: 8}]->(top_gun) MERGE (arya)-[:RATED {score: 1}]->(matrix) MERGE (arya)-[:RATED {score: 10}]->(jerry) MERGE (arya)-[:RATED {score: 10}]->(gruffalo)
MERGE (karin)-[:RATED {score: 9}]->(top_gun) MERGE (karin)-[:RATED {score: 7}]->(matrix) MERGE (karin)-[:RATED {score: 7}]->(home_alone) MERGE (karin)-[:RATED {score: 9}]->(gruffalo)
Added 11 labels, created 11 nodes, set 31 properties, created 20 relationships, completed after 21 ms.
4.1. 흐름
MATCH (p:Person), (m:Movie) OPTIONAL MATCH (p)-[rated:RATED]->(m) WITH {item:id(p), weights: collect(coalesce(rated.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.pearson.stream({ data: data, topK: 0 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Zhen" "Praveena" 0.8865926413116155 "Zhen" "Karin" 0.8320502943378437 "Arya" "Karin" 0.8194651785206903 "Zhen" "Arya" 0.4839533792540704 "Praveena" "Karin" 0.4472135954999579 "Praveena" "Arya" 0.09262336892949784 "Praveena" "Michael" -0.788492846568306 "Zhen" "Michael" -0.9091365607973364 "Michael" "Arya" -0.9551953674747637 "Michael" "Karin" -0.9863939238321437
-> Zhen과 Praveena는 0.88 점으로 가장 비슷합니다. 최대 점수는 1.0입니다. 또한 전혀 유사하지 않은 4 쌍의 사용자가 있습니다. 우리는 아마도 그것들을 걸러 내고 싶을 것입니다. 우리는 similarityCutoff매개 변수 를 전달함으로써 할 수 있습니다 .
MATCH (p:Person), (m:Movie) OPTIONAL MATCH (p)-[rated:RATED]->(m) WITH {item:id(p), weights: collect(coalesce(rated.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.pearson.stream({ data: data, similarityCutoff: 0.1, topK: 0 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity
"Zhen" "Praveena" 0.8865926413116155 "Zhen" "Karin" 0.8320502943378437 "Arya" "Karin" 0.8194651785206903 "Zhen" "Arya" 0.4839533792540704 "Praveena" "Karin" 0.4472135954999579
유사성이없는 사용자가 필터링되었음을 알 수 있습니다. k-Nearest Neighbors 유형 쿼리를 구현하는 경우 대신 k주어진 사용자에 대해 가장 유사한 사용자 를 찾고 싶을 수 있습니다 . topK매개 변수 를 전달하면 됩니다.
MATCH (p:Person), (m:Movie) OPTIONAL MATCH (p)-[rated:RATED]->(m) WITH {item:id(p), weights: collect(coalesce(rated.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.pearson.stream({ data: data, topK:1, similarityCutoff: 0.0 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Zhen" "Praveena" 0.8865926413116155 "Praveena" "Zhen" 0.8865926413116155 "Karin" "Zhen" 0.8320502943378437 "Arya" "Karin" 0.8194651785206903
-> 이러한 결과는 반드시 대칭적인 것은 아닙니다. 예를 들어, Arya와 가장 유사한 사람은 Karin이지만 Karin과 가장 유사한 사람은 Zhen입니다.
4.2. 쓰다
MATCH (p:Person), (m:Movie) OPTIONAL MATCH (p)-[rated:RATED]->(m) WITH {item:id(p), weights: collect(coalesce(rated.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.pearson.write({ data: data, topK: 1, similarityCutoff: 0.1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
nodes similarityPairs writeRelationshipType writeProperty min max mean p95 5 4 "SIMILAR" "score" 0.8194618225097656 0.8865890502929688 0.8561716079711914 0.8865890502929688
다음은 Karin과 가장 유사한 사용자를 찾고 Karin이 평가하지 않은 (아직!) 평가하지 않은 영화를 반환합니다.
MATCH (p:Person {name: 'Karin'})-[:SIMILAR]->(other), (other)-[r:RATED]->(movie) WHERE not((p)-[:RATED]->(movie)) and r.score >= 5 RETURN movie.name AS movie
movie "Jerry Maguire"
4.3. 통계
MATCH (p:Person), (m:Movie) OPTIONAL MATCH (p)-[rated:RATED]->(m) WITH {item:id(p), weights: collect(coalesce(rated.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.pearson.stats({ data: data, topK: 1, similarityCutoff: 0.1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
Neo.ClientError.Statement.SyntaxError Unknown procedure output:
writeRelationshipType(line 10, column 31 (offset: 314)) "YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95"
- 소스 및 대상 ID 지정
다음은 k=1Arya 및 Praveena와 가장 유사한 사람 (예 :)을 찾습니다
MATCH (p:Person), (m:Movie) OPTIONAL MATCH (p)-[rated:RATED]->(m) WITH {item:id(p), name: p.name, weights: collect(coalesce(rated.score, gds.util.NaN()))} AS userData WITH collect(userData) AS personCuisines WITH personCuisines, [value in personCuisines WHERE value.name IN ["Praveena", "Arya"] | value.item ] AS sourceIds CALL gds.alpha.similarity.pearson.stream({ data: personCuisines, sourceIds: sourceIds, topK: 1 }) YIELD item1, item2, similarity WITH gds.util.asNode(item1) AS from, gds.util.asNode(item2) AS to, similarity RETURN from.name AS from, to.name AS to, similarity ORDER BY similarity DESC
from to similarity "Praveena" "Zhen" 0.8865926413116155 "Arya" "Karin" 0.8194651785206903
- 값 건너 뛰기
샘플추가
MERGE (home_alone:Movie {name:'Home Alone'}) SET home_alone.embedding = [0.71, 0.33, 0.81, 0.52, 0.41] MERGE (matrix:Movie {name:'The Matrix'}) SET matrix.embedding = [0.31, 0.72, 0.58, 0.67, 0.31] MERGE (good_men:Movie {name:'A Few Good Men'}) SET good_men.embedding = [0.43, 0.26, 0.98, 0.51, 0.76] MERGE (top_gun:Movie {name:'Top Gun'}) SET top_gun.embedding = [0.12, 0.23, 0.35, 0.31, 0.3] MERGE (jerry:Movie {name:'Jerry Maguire'}) SET jerry.embedding = [0.47, 0.98, 0.81, 0.72, 0]
Set 5 properties, completed after 20 ms.
MATCH (m:Movie) WITH {item:id(m), weights: m.embedding} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.pearson.stream({ data: data, skipValue: null }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Jerry Maguire" "The Matrix" 0.8689113641953199 "The Matrix" "Jerry Maguire" 0.8689113641953199 "A Few Good Men" "Top Gun" 0.6846566091701214 "Top Gun" "A Few Good Men" 0.6846566091701214 "Home Alone" "A Few Good Men" 0.556559508845268 "A Few Good Men" "Home Alone" 0.556559508845268 "The Matrix" "Top Gun" 0.39320549183813097 "Top Gun" "The Matrix" 0.39320549183813097 "Jerry Maguire" "Home Alone" 0.10026787755714502 "Home Alone" "Jerry Maguire" 0.10026787755714502 "Jerry Maguire" "Top Gun" 0.056232940630734043 "Top Gun" "Jerry Maguire" 0.056232940630734043 "Home Alone" "Top Gun" 0.006048691083898151 "The Matrix" "Home Alone" -0.23435051666541426 "A Few Good Men" "The Matrix" -0.2545273235448378
- 사이퍼 투영
WITH "MATCH (person:Person)-[rated:RATED]->(c) RETURN id(person) AS item, id(c) AS category, rated.score AS weight" AS query CALL gds.alpha.similarity.pearson({ data: query, graph: 'cypher', topK: 1, similarityCutoff: 0.1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
There is no procedure with the name gds.alpha.similarity.pearson registered for this database instance. Please ensure you've spelled the procedure name correctly and that the procedure is properly deployed.
- 구문
CALL gds.alpha.similarity.pearson.write(configuration: Map) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100
Variable configuration not defined (line 1, column 41 (offset: 40))
"CALL gds.alpha.similarity.pearson.write(configuration: Map)"
유클리드 거리
n 차원 공간에서 두 점 사이의 직선 거리를 측정합니다. Euclidean Distance 함수는 두 숫자 목록의 유사성을 계산합니다.
RETURN gds.alpha.similarity.euclideanDistance([3,8,7,5,2,9], [10,8,6,6,4,5]) AS similarity
similarity 8.426149773176359
예)
MERGE (french:Cuisine {name:'French'}) MERGE (italian:Cuisine {name:'Italian'}) MERGE (indian:Cuisine {name:'Indian'}) MERGE (lebanese:Cuisine {name:'Lebanese'}) MERGE (portuguese:Cuisine {name:'Portuguese'}) MERGE (british:Cuisine {name:'British'}) MERGE (mauritian:Cuisine {name:'Mauritian'})
MERGE (zhen:Person {name: "Zhen"}) MERGE (praveena:Person {name: "Praveena"}) MERGE (michael:Person {name: "Michael"}) MERGE (arya:Person {name: "Arya"}) MERGE (karin:Person {name: "Karin"})
MERGE (praveena)-[:LIKES {score: 9}]->(indian) MERGE (praveena)-[:LIKES {score: 7}]->(portuguese) MERGE (praveena)-[:LIKES {score: 8}]->(british) MERGE (praveena)-[:LIKES {score: 1}]->(mauritian)
MERGE (zhen)-[:LIKES {score: 10}]->(french) MERGE (zhen)-[:LIKES {score: 6}]->(indian) MERGE (zhen)-[:LIKES {score: 2}]->(british)
MERGE (michael)-[:LIKES {score: 8}]->(french) MERGE (michael)-[:LIKES {score: 7}]->(italian) MERGE (michael)-[:LIKES {score: 9}]->(indian) MERGE (michael)-[:LIKES {score: 3}]->(portuguese)
MERGE (arya)-[:LIKES {score: 10}]->(lebanese) MERGE (arya)-[:LIKES {score: 10}]->(italian) MERGE (arya)-[:LIKES {score: 7}]->(portuguese) MERGE (arya)-[:LIKES {score: 9}]->(mauritian)
MERGE (karin)-[:LIKES {score: 9}]->(lebanese) MERGE (karin)-[:LIKES {score: 7}]->(italian) MERGE (karin)-[:LIKES {score: 10}]->(portuguese)
Added 12 labels, created 12 nodes, set 30 properties, created 18 relationships, completed after 1034 ms.
다음은 Zhen과 Praveena의 유클리드 거리를 반환합니다.
MATCH (p1:Person {name: 'Zhen'})-[likes1:LIKES]->(cuisine) MATCH (p2:Person {name: 'Praveena'})-[likes2:LIKES]->(cuisine) RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.euclideanDistance(collect(likes1.score), collect(likes2.score)) AS similarity
from to similarity "Zhen" "Praveena" 6.708203932499369
다음은 Zhen과 공통 요리를 가진 다른 사람들의 유클리드 거리를 반환합니다.
MATCH (p1:Person {name: 'Zhen'})-[likes1:LIKES]->(cuisine) MATCH (p2:Person)-[likes2:LIKES]->(cuisine) WHERE p2 <> p1 RETURN p1.name AS from, p2.name AS to, gds.alpha.similarity.euclideanDistance(collect(likes1.score), collect(likes2.score)) AS similarity ORDER BY similarity DESC
from to similarity "Zhen" "Praveena" 6.708203932499369 "Zhen" "Michael" 3.605551275463989
- 유클리드 거리 알고리즘 절차 샘플
유클리드 거리 프로시저는 모든 항목 쌍 간의 유사성을 계산합니다. 이것은 대칭 알고리즘입니다. 즉, 항목 A와 항목 B의 유사성을 계산 한 결과는 항목 B와 항목 A의 유사성을 계산 한 것과 같습니다. 따라서 각 노드 쌍에 대한 점수를 한 번 계산할 수 있습니다. 우리는 항목의 유사성을 스스로 계산하지 않습니다.
샘플추가
MERGE (french:Cuisine {name:'French'}) MERGE (italian:Cuisine {name:'Italian'}) MERGE (indian:Cuisine {name:'Indian'}) MERGE (lebanese:Cuisine {name:'Lebanese'}) MERGE (portuguese:Cuisine {name:'Portuguese'}) MERGE (british:Cuisine {name:'British'}) MERGE (karin:Person {name: "Karin"}) MERGE (mauritian:Cuisine {name:'Mauritian'}) MERGE (zhen:Person {name: "Zhen"}) MERGE (praveena:Person {name: "Praveena"}) MERGE (michael:Person {name: "Michael"}) MERGE (arya:Person {name: "Arya"})
MERGE (praveena)-[:LIKES {score: 9}]->(indian) MERGE (praveena)-[:LIKES {score: 7}]->(portuguese) MERGE (praveena)-[:LIKES {score: 8}]->(british) MERGE (praveena)-[:LIKES {score: 1}]->(mauritian)
MERGE (zhen)-[:LIKES {score: 10}]->(french) MERGE (zhen)-[:LIKES {score: 6}]->(indian) MERGE (zhen)-[:LIKES {score: 2}]->(british) MERGE (michael)-[:LIKES {score: 8}]->(french) MERGE (michael)-[:LIKES {score: 7}]->(italian) MERGE (michael)-[:LIKES {score: 9}]->(indian) MERGE (michael)-[:LIKES {score: 3}]->(portuguese) MERGE (arya)-[:LIKES {score: 10}]->(lebanese) MERGE (arya)-[:LIKES {score: 10}]->(italian) MERGE (arya)-[:LIKES {score: 7}]->(portuguese) MERGE (arya)-[:LIKES {score: 9}]->(mauritian)
MERGE (karin)-[:LIKES {score: 9}]->(lebanese) MERGE (karin)-[:LIKES {score: 7}]->(italian) MERGE (karin)-[:LIKES {score: 10}]->(portuguese)
Completed after 31 ms ->순서 수정
4.1. 흐름
다음은 교차점 및 유클리드 유사성과 함께 노드 쌍의 스트림을 반환합니다.
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.stream({ data: data, topK: 0 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity
from to similarity "Praveena" "Karin" 3.0 "Zhen" "Michael" 3.605551275463989 "Praveena" "Michael" 4.0 "Arya" "Karin" 4.358898943540674 "Michael" "Arya" 5.0 "Zhen" "Praveena" 6.708203932499369 "Michael" "Karin" 7.0 "Praveena" "Arya" 8.0 "Zhen" "Arya" NaN "Zhen" "Karin" NaN
->Praveena와 Karin은 유클리드 거리 3.0으로 가장 유사한 음식 선호도를 가지고 있습니다. 여기서 점수가 낮을수록 좋습니다. 0 점은 사용자가 동일한 선호도를 가지고 있음을 나타냅니다.
목록 맨 아래에서 Zhen과 Arya, Zhen과 Karin이 NaN. 음식 선호도가 겹치지 않기 때문에이 결과를 얻습니다. gds.util.isFinite함수를 사용하여 이러한 결과를 필터링 할 수 있습니다 .
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.stream({ data: data, topK: 0 }) YIELD item1, item2, count1, count2, similarity WHERE gds.util.isFinite(similarity) RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity
from to similarity "Praveena" "Karin" 3.0 "Zhen" "Michael" 3.605551275463989 "Praveena" "Michael" 4.0 "Arya" "Karin" 4.358898943540674 "Michael" "Arya" 5.0 "Zhen" "Praveena" 6.708203932499369 "Michael" "Karin" 7.0 "Praveena" "Arya" 8.0
유사성이 4 이상인 사용자가 결과에 반환되는 것을 보지 않기로 결정할 수 있습니다. 그렇다면 similarityCutoff매개 변수 를 전달하여 필터링 할 수 있습니다 .
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.stream({ data: data, similarityCutoff: 4.0, topK: 0 }) YIELD item1, item2, count1, count2, similarity WHERE gds.util.isFinite(similarity) RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity
from to similarity "Praveena" "Karin" 3.0 "Zhen" "Michael" 3.605551275463989 "Praveena" "Michael" 4.0
점수가 높은 사용자가 필터링되었음을 알 수 있습니다. k-Nearest Neighbors 유형 쿼리를 구현하는 경우 대신 k 주어진 사용자에 대해 가장 유사한 사용자 를 찾고 싶을 수 있습니다 . topK매개 변수 를 전달하면 됩니다.
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.stream({ data: data, topK: 1 }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY from
from to similarity "Arya" "Karin" 4.358898943540674 "Karin" "Praveena" 3.0 "Michael" "Zhen" 3.605551275463989 "Praveena" "Karin" 3.0 "Zhen" "Michael" 3.605551275463989
-> 이러한 결과는 반드시 대칭적인 것은 아닙니다. 예를 들어, Arya와 가장 유사한 사람은 Karin이지만 Karin과 가장 유사한 사람은 Praveena입니다.
4.2. 쓰다
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.write({ data: data, topK: 1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
nodes similarityPairs writeRelationshipType writeProperty min max mean p95 5 5 "SIMILAR" "score" 3.0 4.3589019775390625 3.5139984130859374 4.3589019775390625
그런 다음 쿼리를 작성하여 우리와 비슷한 다른 사람들이 좋아할 수있는 요리 유형을 알아낼 수 있습니다. 다음은 Praveena와 가장 유사한 사용자를 찾고 Praveena가 (아직!) 좋아하지 않는 좋아하는 요리를 반환합니다.
MATCH (p:Person {name: "Praveena"})-[:SIMILAR]->(other), (other)-[:LIKES]->(cuisine) WHERE not((p)-[:LIKES]->(cuisine)) RETURN cuisine.name AS cuisine
cuisine "Italian" "Lebanese"
4.3. 통계
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.stats({ data: data, topK: 1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
Unknown procedure output: writeRelationshipType (line 9, column 31 (offset: 293))
"YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95"
^
5. 소스 및 대상 ID 지정
때로는 모든 쌍의 유사성을 계산하지 않고 서로 비교할 항목의 하위 집합을 지정하는 경우가 있습니다.
구성에서 sourceIds및 targetIds키를 사용하여 이를 수행합니다 .
다음은 k=1 Arya 및 Praveena와 가장 유사한 사람 (예 :)을 찾습니다
MATCH (p:Person), (c:Cuisine) OPTIONAL MATCH (p)-[likes:LIKES]->(c) WITH {item:id(p), name: p.name, weights: collect(coalesce(likes.score, gds.util.NaN()))} AS userData WITH collect(userData) AS personCuisines WITH personCuisines, [value in personCuisines WHERE value.name IN ["Praveena", "Arya"] | value.item ] AS sourceIds CALL gds.alpha.similarity.euclidean.stream({ data: personCuisines, sourceIds: sourceIds, topK: 1 }) YIELD item1, item2, similarity WITH gds.util.asNode(item1) AS from, gds.util.asNode(item2) AS to, similarity RETURN from.name AS from, to.name AS to, similarity ORDER BY similarity DESC
from to similarity "Arya" "Karin" 4.358898943540674 "Praveena" "Karin" 3.0
- 값 건너 뛰기 기본적으로 skipValue매개 변수는 gds.util.NaN()입니다. 알고리즘은 모든 값을에 대해 검사하여 skipValue해당 값이 유사성 결과의 일부로 간주되어야하는지 여부를 결정합니다. 값을 건너 뛸 수없는 경우로 설정 skipValue하여 건너 뛰기를 비활성화 할 수 있습니다.
MERGE (french:Cuisine {name:'French'}) SET french.embedding = [0.71, 0.33, 0.81, 0.52, 0.41] MERGE (italian:Cuisine {name:'Italian'}) SET italian.embedding = [0.31, 0.72, 0.58, 0.67, 0.31] MERGE (indian:Cuisine {name:'Indian'}) SET indian.embedding = [0.43, 0.26, 0.98, 0.51, 0.76] MERGE (lebanese:Cuisine {name:'Lebanese'}) SET lebanese.embedding = [0.12, 0.23, 0.35, 0.31, 0.39] MERGE (portuguese:Cuisine {name:'Portuguese'}) SET portuguese.embedding = [0.47, 0.98, 0.81, 0.72, 0.89] MERGE (british:Cuisine {name:'British'}) SET british.embedding = [0.94, 0.12, 0.23, 0.4, 0.71] MERGE (mauritian:Cuisine {name:'Mauritian'}) SET mauritian.embedding = [0.31, 0.56, 0.98, 0.21, 0.62]
Set 7 properties, completed after 24 ms.
MATCH (c:Cuisine) WITH {item:id(c), weights: c.embedding} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.euclidean.stream({ data: data, skipValue: null }) YIELD item1, item2, count1, count2, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "British" "Indian" 0.9256349172324908 "British" "Lebanese" 0.8996666049153985 "Lebanese" "French" 0.783709129715866 "Portuguese" "Indian" 0.7809609465267774 "Indian" "Portuguese" 0.7809609465267774 "Lebanese" "Mauritian" 0.7776888838089432 "Portuguese" "Mauritian" 0.7509327533141699 "British" "French" 0.7333484846919642 "Mauritian" "Italian" 0.7023531875061151 "Portuguese" "Italian" 0.696419413859206 "Italian" "Portuguese" 0.696419413859206 "Italian" "Lebanese" 0.6819824044651006 "Lebanese" "Italian" 0.6819824044651006 "French" "Italian" 0.6304760106459246 "Italian" "French" 0.6304760106459246 "Mauritian" "French" 0.6180614856144977 "French" "Mauritian" 0.6180614856144977 "French" "Indian" 0.48456165758342873 "Indian" "French" 0.48456165758342873 "Mauritian" "Indian" 0.46260134024881516 "Indian" "Mauritian" 0.46260134024881516
- 사이퍼 투영
WITH "MATCH (person:Person)-[likes:LIKES]->(c) RETURN id(person) AS item, id(c) AS category, likes.score AS weight" AS query CALL gds.alpha.similarity.euclidean.write({ data: query, graph: 'cypher', topK: 1, similarityCutoff: 4.0 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
nodes similarityPairs writeRelationshipType writeProperty min max mean p95 5 5 "SIMILAR" "score" 0.0 3.6055450439453125 2.642218017578125 3.6055450439453125
- 구문
CALL gds.alpha.similarity.euclidean.write(configuration: Map) YIELD nodes, similarityPair, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100
Variable configuration not defined (line 1, column 43 (offset: 42))
"CALL gds.alpha.similarity.euclidean.write(configuration: Map)"
중복 유사성
측정 값은 두 세트간에 중복됩니다. 두 세트 중 더 작은 크기로 나눈 두 세트의 교차점 크기로 정의됩니다. Overlap Similarity 알고리즘을 사용하여 어떤 것이 다른 것의 하위 집합인지 알아낼 수 있습니다. 그런 다음 Jesús Barrasa가 설명한대로 이러한 계산 된 하위 집합을 사용 하여 태그가 지정된 데이터에서 분류를 학습 할 수 있습니다.
RETURN gds.alpha.similarity.overlap([1,2,3], [1,2,4,5]) AS similarity
similarity 0.6666666666666666
예)
CREATE (fahrenheit451:Book {title:'Fahrenheit 451'}), (dune:Book {title:'Dune'}), (hungerGames:Book {title:'The Hunger Games'}), (nineteen84:Book {title:'1984'}), (gatsby:Book {title:'The Great Gatsby'}),
(scienceFiction:Genre {name: "Science Fiction"}), (fantasy:Genre {name: "Fantasy"}), (dystopia:Genre {name: "Dystopia"}), (classics:Genre {name: "Classics"}),
(fahrenheit451)-[:HAS_GENRE]->(dystopia), (fahrenheit451)-[:HAS_GENRE]->(scienceFiction), (fahrenheit451)-[:HAS_GENRE]->(fantasy), (fahrenheit451)-[:HAS_GENRE]->(classics),
(hungerGames)-[:HAS_GENRE]->(scienceFiction), (hungerGames)-[:HAS_GENRE]->(fantasy),
(nineteen84)-[:HAS_GENRE]->(scienceFiction), (nineteen84)-[:HAS_GENRE]->(dystopia), (nineteen84)-[:HAS_GENRE]->(classics),
(dune)-[:HAS_GENRE]->(scienceFiction), (dune)-[:HAS_GENRE]->(fantasy), (dune)-[:HAS_GENRE]->(classics),
(gatsby)-[:HAS_GENRE]->(classics)
Added 9 labels, created 9 nodes, set 9 properties, created 13 relationships, completed after 34 ms.
4.1. 흐름
MATCH (book:Book)-[:HAS_GENRE]->(genre) WITH {item:id(genre), categories: collect(id(book))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.overlap.stream({data: data}) YIELD item1, item2, count1, count2, intersection, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, count1, count2, intersection, similarity ORDER BY similarity DESC
from to count1 count2 intersection similarity "Fantasy" "Science Fiction" 3 4 3 1.0 "Dystopia" "Classics" 2 4 2 1.0 "Dystopia" "Science Fiction" 2 4 2 1.0 "Science Fiction" "Classics" 4 4 3 0.75 "Fantasy" "Classics" 3 4 2 0.6666666666666666 "Dystopia" "Fantasy" 2 3 1 0.5
다음은 유사성이 0.75 이상인 노드 쌍의 스트림과 교차 및 중복 유사성을 반환합니다.
MATCH (book:Book)-[:HAS_GENRE]->(genre) WITH {item:id(genre), categories: collect(id(book))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.overlap.stream({ data: data, similarityCutoff: 0.75 }) YIELD item1, item2, count1, count2, intersection, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, count1, count2, intersection, similarity ORDER BY similarity DESC
from to count1 count2 intersection similarity "Fantasy" "Science Fiction" 3 4 3 1.0 "Dystopia" "Classics" 2 4 2 1.0 "Dystopia" "Science Fiction" 2 4 2 1.0 "Science Fiction" "Classics" 4 4 3 0.75
MATCH (book:Book)-[:HAS_GENRE]->(genre) WITH {item:id(genre), categories: collect(id(book))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.overlap.stream({ data: data, topK: 2 }) YIELD item1, item2, count1, count2, intersection, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, count1, count2, intersection, similarity ORDER BY from
from to count1 count2 intersection similarity "Dystopia" "Classics" 2 4 2 1.0 "Dystopia" "Science Fiction" 2 4 2 1.0 "Fantasy" "Science Fiction" 3 4 3 1.0 "Fantasy" "Classics" 3 4 2 0.6666666666666666 "Science Fiction" "Classics" 4 4 3 0.75
4.2. 쓰다
MATCH (book:Book)-[:HAS_GENRE]->(genre) WITH {item:id(genre), categories: collect(id(book))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.overlap.write({ data: data, topK: 2, similarityCutoff: 0.5 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
nodes similarityPairs writeRelationshipType writeProperty min max mean p95 4 5 "NARROWER_THAN" "score" 0.6666641235351562 1.0000038146972656 0.8833351135253906 1.0000038146972656
MATCH path = (fantasy:Genre {name: "Fantasy"})-[:NARROWER_THAN*]->(genre) RETURN [node in nodes(path) | node.name] AS hierarchy ORDER BY length(path)
hierarchy ["Fantasy", "Classics"] ["Fantasy", "Science Fiction"] ["Fantasy", "Science Fiction", "Classics"]
4.3. 통계
MATCH (book:Book)-[:HAS_GENRE]->(genre) WITH {item:id(genre), categories: collect(id(book))} AS userData WITH collect(userData) AS data CALL gds.alpha.similarity.overlap.stats({ data: data, topK: 2, similarityCutoff: 0.5 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
Unknown procedure output: writeRelationshipType (line 9, column 31 (offset: 265))
"YIELD nodes, similarityPairs, writeRelationshipType,writeProperty, min, max, mean, p95"
^
- 소스 및 대상 ID 지정
다음은 Fantasy및 Classics장르에 대한 슈퍼 장르를 반환합니다 .
MATCH (book:Book)-[:HAS_GENRE]->(genre) WITH {item:id(genre), name: genre.name, categories: collect(id(book))} AS userData WITH collect(userData) AS data WITH data, [value in data WHERE value.name IN ["Fantasy", "Classics"] | value.item ] AS sourceIds CALL gds.alpha.similarity.overlap.stream({ data: data, sourceIds: sourceIds }) YIELD item1, item2, count1, count2, intersection, similarity RETURN gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY similarity DESC
from to similarity "Fantasy" "Science Fiction" 1.0 "Classics" "Science Fiction" 0.75 "Fantasy" "Classics" 0.6666666666666666
- 구문
CALL gds.alpha.similarity.overlap.write(configuration: Map) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, stdDev, p25, p50, p75, p90, p95, p99, p999, p100
Variable configuration not defined (line 1, column 41 (offset: 40))
"CALL gds.alpha.similarity.overlap.write(configuration: Map)"
^
근사치 인접 이웃 (ANN)
항목의 유사성은 Jaccard Similarity , Cosine Similarity , Euclidean Distance 또는 Pearson Similarity를 기반으로 계산됩니다 .
예)
CREATE (french:Cuisine {name:'French'}), (italian:Cuisine {name:'Italian'}), (indian:Cuisine {name:'Indian'}), (lebanese:Cuisine {name:'Lebanese'}), (portuguese:Cuisine {name:'Portuguese'}),
(zhen:Person {name: 'Zhen'}), (praveena:Person {name: 'Praveena'}), (michael:Person {name: 'Michael'}), (arya:Person {name: 'Arya'}), (karin:Person {name: 'Karin'}),
(praveena)-[:LIKES]->(indian), (praveena)-[:LIKES]->(portuguese),
(zhen)-[:LIKES]->(french), (zhen)-[:LIKES]->(indian),
(michael)-[:LIKES]->(french), (michael)-[:LIKES]->(italian), (michael)-[:LIKES]->(indian),
(arya)-[:LIKES]->(lebanese), (arya)-[:LIKES]->(italian), (arya)-[:LIKES]->(portuguese),
(karin)-[:LIKES]->(lebanese), (karin)-[:LIKES]->(italian)
Added 10 labels, created 10 nodes, set 10 properties, created 12 relationships, completed after 21 ms.
다음은 Jaccard 유사성에 따라 노드와 가장 유사한 최대 3 개의 노드와 함께 노드 스트림을 반환합니다.
MATCH (p:Person)-[:LIKES]->(cuisine) WITH {item:id(p), categories: collect(id(cuisine))} AS userData WITH collect(userData) AS data CALL gds.alpha.ml.ann.stream({ data: data, algorithm: 'jaccard', similarityCutoff: 0.1, concurrency: 1 }) YIELD item1, item2, similarity return gds.util.asNode(item1).name AS from, gds.util.asNode(item2).name AS to, similarity ORDER BY from
from to similarity "Arya" "Karin" 0.6666666666666666 "Arya" "Michael" 0.2 "Karin" "Arya" 0.6666666666666666 "Karin" "Michael" 0.25 "Michael" "Zhen" 0.6666666666666666 "Michael" "Karin" 0.25 "Michael" "Arya" 0.2 "Praveena" "Zhen" 0.3333333333333333 "Praveena" "Arya" 0.25 "Zhen" "Praveena" 0.3333333333333333
Arya와 Karin, Zhen과 Michael은 0.66의 유사성에 대해 두 개의 겹치는 요리로 가장 유사한 음식 선호도를 가지고 있습니다. 우리는 또한 전혀 유사하지 않은 3 쌍의 사용자가 있습니다. 우리는 아마도 그것들을 걸러 내고 싶을 것입니다. 우리는 similarityCutoff매개 변수 를 전달함으로써 할 수 있습니다 .
MATCH (p:Person)-[:LIKES]->(cuisine) WITH {item:id(p), categories: collect(id(cuisine))} AS userData WITH collect(userData) AS data CALL gds.alpha.ml.ann.write({ algorithm: 'jaccard', data: data, similarityCutoff: 0.1, showComputations: true, concurrency: 1 }) YIELD nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95 RETURN nodes, similarityPairs, writeRelationshipType, writeProperty, min, max, mean, p95
nodes similarityPairs writeRelationshipType writeProperty min max mean p95 5 10 "SIMILAR" "score" 0.19999980926513672 0.6666669845581055 0.3816666603088379 0.6666669845581055
그런 다음 쿼리를 작성하여 우리와 비슷한 다른 사람들이 좋아할 수있는 요리 유형을 알아낼 수 있습니다.
MATCH (p:Person {name: 'Praveena'})-[:SIMILAR]->(other), (other)-[:LIKES]->(cuisine) WHERE not((p)-[:LIKES]->(cuisine)) RETURN cuisine.name AS cuisine, count(*) AS count ORDER BY cuisine DESC
cuisine count "Lebanese" 1 "Italian" 1 "French" 1