Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Neo4j free text search combined with relation query

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.

like image 390
Roee Gavirel Avatar asked Apr 14 '19 11:04

Roee Gavirel


1 Answers

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.*'
...
like image 62
InverseFalcon Avatar answered Sep 24 '22 01:09

InverseFalcon