Reputation: 101
I'm trying to develop a Neo4j search query to find similar looking photos.
I have 62 nodes labeled "Likeness" that represent photos that all other nodes labeled "Photo" will be compared to. My data looks like this:
(p:Photo {name: 'treehouse'})-[r:LOOKS_LIKE {weight: 0.874655}]->(l:Likeness {name: 'lighthouse'})
(p:Photo {name: 'cat'})-[r:LOOKS_LIKE {weight: 0.00454}]->(l:Likeness {name: 'lighthouse'})
(p:Photo {name: 'house'})-[r:LOOKS_LIKE {weight: 0.4768}]->(l:Likeness {name: 'lighthouse'})
etc...
All relationship weights are between 0 and 1.
So an example search might be:
[
{name: 'lighthouse', value: 0.856378},
{name: 'car', value: 0.17854},
{name: 'tank', value: 0.034523},
{name: 'pencil', value: 0.078902}
]
How do I return nodes in order of similarity (distance from) these nodes and weights?
Upvotes: 0
Views: 37
Reputation: 881
Try this query. It finds all the matches for your search, and then calculates the similarity as 1 minus the difference between the search and the weight of the relationship. It also returns the individual likenesses that matched each photo as a map.
UNWIND [
{name: 'lighthouse', value: 0.856378},
{name: 'car', value: 0.17854},
{name: 'tank', value: 0.034523},
{name: 'pencil', value: 0.078902}
] AS s
MATCH (p:Photo)-[r:LOOKS_LIKE]->(l:Likeness)
WHERE l.name = s.name
RETURN p.name, SUM(1 - abs(r.weight - s.value)) AS similarity,
COLLECT({likeness:l.name, weight:r.weight, similarity: 1 - abs(r.weight - s.value)}) AS matches
ORDER BY similarity desc
Upvotes: 1
Reputation: 881
You can use order by and limit clauses to return a specified number of sorted results.
Try something like this to see which five likenesses are the closest match to the treehouse photo.
MATCH (p:Photo {name:'treehouse'})-[r:LOOKS_LIKE]->(l:Likeness)
RETURN l.name, r.weight
ORDER BY r.weight DESC
LIMIT 5
Upvotes: 0