Neo4j free text search combined with relation query
Asked Answered
A

3

9

I see that Neo4j have Indexes to support full-text search. But I can't find examples in the documentation on how to use this ability with regular relations query.

For example, I have the following structure: (:User)->[:Wrote]->(:Review)->[:Reviewing]->(:Movie)

I want to search Reviews with the full-text-search ability but only for a specific user. So user '123' want to search all his reviews with 'great acting' in them. So search the user's reviews would be MATCH (:User { id: 123 })-[w]->(review). While searching for reviews with the words 'great' and 'acting' would be CALL db.index.fulltext.queryNodes("reviews", "great acting")

What I can't figure out is how to combine the two with AND logic.

EDIT
I figured I can do the following thing:

CALL db.index.fulltext.queryNodes("reviews", "great acting") YIELD node as reviews
MATCH (:User { id: 123 })-[w]->(reviews)

The thing is, I may have millions of reviews with "great" or "acting" in them while the relevant user probably doesn't have more than 10s reviews. It doesn't sound very efficient.

Anticlimax answered 14/4, 2019 at 11:20 Comment(0)
H
6

In this particular case full text search won't be a help performance-wise, as this would select all reviews containing 'great acting' (of which there are likely a great, great many) and then you would need to filter to those belonging to the user in question.

This is far less performant than matching to the reviews of the user in question (of which there should be comparatively far far fewer) and then filtering those for the word 'great acting'.

You can use the CONTAINS keyword in your WHERE clause to ensure the property contains the given substring, as in Raj's answer (though this is case sensitive):

MATCH (:User{ id: 123 })->[:Wrote]->(review:Review)->[:Reviewing]->(:Movie) 
WHERE review.text CONTAINS 'great acting'
...

You can also create an index on this, though it's far more efficient if it doesn't get used for lookup here and instead starts with the user node (you can EXPLAIN the query to determine what indexes are used to find the starting node(s)).

If you need case insensitive searching of keywords, you can use the =~ regex operator for this, though this is not index-backed. For example:

MATCH (:User{ id: 123 })->[:Wrote]->(review:Review)->[:Reviewing]->(:Movie) 
WHERE review.text =~ '(?i).*great acting.*'
...
Hyatt answered 16/4, 2019 at 4:27 Comment(1)
Thank for the provided alternatives. I understand now that since the full-text-search is based on the Lucene index it can't be made on a subset of nodes.Anticlimax
T
1

You can use following query with the help of APOC library. Assuming you have unique identifier for reviews (id)

MATCH (:User { id: 123 })-[w]->(reviews)
WITH collect(reviews.id) AS reviewIds
WITH "(" + apoc.text.join(reviewIds, " OR ") + ")" AS str
CALL db.index.fulltext.queryNodes("reviews", "text:great acting id:" + str)
YIELD node as reviews 
Typeset answered 14/8, 2022 at 16:36 Comment(0)
O
0

Don't know how to use the full-text search in this case but I think you can use a single property index with CONTAINS predicate in this case.

If you are searching over a single property of node then you can index that property and search with CONTAINS predicate.

Create Index:

CREATE INDEX ON :Review(text)

Search query:

MATCH (:User{ id: 123 })->[:Wrote]->(review:Review)->[:Reviewing]->(:Movie) 
WHERE review.text CONTAINS 'love'

P.S.:

Another approach could be first search review nodes using full-text search and then filter these review nodes for a user by matching in the above query. I doubt this will do any performance improvements.

Occam answered 14/4, 2019 at 12:4 Comment(2)
I guess using 'love' was a bad example. I want to support any free-text the user may supply, and for that, I would like to make use of the fuzziness and other full-text search capabilities. Regarding the Another approach, I tried that but it doesn't seem reasonable. I may have a million reviews with the word 'love' but the relevant user may have 5 reviews altogether. So it seems to go the other way around...Anticlimax
Right, I am also searching for the same. We should be able to search in the set of selected user's reviews. You can post this on the neo4j community page here community.neo4j.comOccam

© 2022 - 2024 — McMap. All rights reserved.