First of all, the technologies that we’re using are Neo4j, Spring and Spring Data Neo4j (all latest stable versions).
We’re having the requirement that users should be able to search for all our entities seperately and also to provide all global search for all entities. I’m hoping the gather suggestions on how to implement the global search. Below is some (simplified!) code that shows how I query my entities. Each entity uses its own Lucene index.
The entity structure:
@NodeEntity
public abstract class BaseEntity {
@GraphId
private Long id;
}
@NodeEntity
public class A extends BaseEntity {
private static final String INDEX = "A_Index";
public static final String SEARCH_QUERY = "START a=node:" + INDEX + "({name}) RETURN a";
@Indexed(indexType = IndexType.FULLTEXT, indexName = INDEX)
@NotBlank
private String name;
}
@NodeEntity
public class B extends BaseEntity {
private static final String INDEX = "B_Index";
public static final String SEARCH_QUERY = "START b=node:" + INDEX + "({name}) RETURN b";
@Indexed(indexType = IndexType.FULLTEXT, indexName = INDEX)
@NotBlank
private String name;
}
The repository classes:
@Repository
public interface ARepository extends GraphRepository<A> {
@Query(A.SEARCH_QUERY)
List<A> find(@Param("name") String name, Pageable pageable);
}
@Repository
public interface BRepository extends GraphRepository<B> {
@Query(B.SEARCH_QUERY)
List<B> find(@Param("name") String name, Pageable pageable);
}
How I access the repository classes (again, very simplified):
@Service
public class Service {
@Autowired
private ARepository repository;
public List<A> search(final String name) {
return repository.find("name:*" + name + "*", null);
}
}
So, this all works great when you search a single entity type. Could someone suggest what the best approach is the implement a global search which searches for every entity type?
Thinks I’ve been thinking about:
-
Use a single Lucene index, instead of an index per entity. Provide a
fieldName in @Indexed like “a.name” or “b.name”. Then use every field
name in a single query like “globalIndex:(a.name:foo OR
b.name:foo). (actually not sure whether this is possible) -
Launch a separate search call for every entity type and combine the
results. It will be difficult to implement paging and sorting based
on the index score though.
I’m not worried about performance, because we’ll be using a relatively small dataset.
A final question: are the results that are returned from a Cypher Lucene query always sorted on their index score? If not, how should I do this in SDN?
I think your first option makes the most sense.
In general you can also use
indexLevel=Level.CLASSto get a global index over all your entities (or use the same index-name for all). And then during the query if you want to filter by type also add a where filter:where a.__type__ = {fqn}fqn being the fully qualified name (or if you use@TypeAliasthat value)Right now sorting by score is not supported, in general cypher only sorts by things you can access in the graph directly.
P.S. It would be cool though to have an annotation that takes multiple @Indexed annotations on a single field and then honor all of them (although that will introduce issues if you want to infer an index from a field). Feel free to raise an issue on the SDN JIRA