David Apple
David Apple

Reputation: 101

Neo4j multidimensional search

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

Answers (2)

Nathan Smith
Nathan Smith

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

Nathan Smith
Nathan Smith

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

Related Questions