0

I want to find a set of User vertices that match a given search string. These vertices have four String properties to match against - FIRST_NAME, LAST_NAME, DISPLAY_NAME and EMAIL. My query is constructed like so:

Query

GraphTraversal<Vertex, Vertex> query = GraphFactory.getDefault().traversal().V()
    .hasLabel(VertexLabel.USER.name())
    .or(    __.has(PropertyKey.EMAIL_LC.name(), Text.textRegex(regex)),
            __.has(PropertyKey.DISPLAY_NAME_LC.name(), Text.textRegex(regex)),
            __.has(PropertyKey.FIRST_NAME.name(), Text.textRegex(regex)),
            __.has(PropertyKey.LAST_NAME.name(), Text.textRegex(regex)));

To answer it, there is one main, MIXED index in place (commented "user search"), amongst others to ensure uniqueness / match against a single property.

Index

//Unique Email Addresses - COMPOSITE
mgmt.buildIndex("byEmailComp", Vertex.class)
    .addKey(emailLowercaseKey)
    .indexOnly(userLabel)
    .unique()
    .buildCompositeIndex();

//Unique Email Addresses - MIXED
mgmt.buildIndex("byEmailMixed", Vertex.class)
    .addKey(emailLowercaseKey, Mapping.TEXTSTRING.asParameter())
    .indexOnly(userLabel)
    .buildMixedIndex("search");

//Unique Display Name - COMPOSITE
mgmt.buildIndex("byDisplayNameComp", Vertex.class)
    .addKey(displayNameLowercaseKey)
    .indexOnly(userLabel)
    .unique()
    .buildCompositeIndex();

//Unique Display Name - MIXED
mgmt.buildIndex("byDisplayNameMixed", Vertex.class)
    .indexOnly(userLabel)
    .addKey(displayNameLowercaseKey, Mapping.TEXTSTRING.asParameter())
    .buildMixedIndex("search");

//User search - MIXED
mgmt.buildIndex("userSearch", Vertex.class)
    .indexOnly(userLabel)
    .addKey(displayNameLowercaseKey, Mapping.TEXTSTRING.asParameter())
    .addKey(emailLowercaseKey, Mapping.TEXTSTRING.asParameter())
    .addKey(firstNameKey, Mapping.TEXTSTRING.asParameter())
    .addKey(lastNameKey, Mapping.TEXTSTRING.asParameter())
    .buildMixedIndex("search");

When running the query, an exception is thrown.

Query needs suitable index to be answered [(~label = USER)]:VERTEX

However, if I match against a property at a time, no exception is thrown. Like so:

GraphFactory.getDefault().traversal().V()
    .hasLabel(VertexLabel.USER.name())
    .has(PropertyKey.EMAIL_LC.name(), Text.textRegex(regex));

// or

GraphFactory.getDefault().traversal().V()
    .hasLabel(VertexLabel.USER.name())
    .has(PropertyKey.DISPLAY_NAME_LC.name(), Text.textRegex(regex));

// or...

How could I restructure the query and/or index for this to work?

Double M
  • 1,449
  • 1
  • 12
  • 29

1 Answers1

3

Try to use a direct index query:

final String searchTerm =
    "v." + PropertyKey.EMAIL_LC.name() + ":(" + regex + ") OR " +
    "v." + PropertyKey.DISPLAY_NAME_LC.name() + ":(" + regex + ") OR " +
    "v." + PropertyKey.FIRST_NAME.name() + ":(" + regex + ") OR " +
    "v." + PropertyKey.LAST_NAME.name() + ":(" + regex + ")";

GraphFactory.getDefault().indexQuery("userSearch", searchTerm).vertices()

The great thing about direct index queries is, that you can also use things like query boosting, which comes handy if you search through multiple fields.

Daniel Kuppitz
  • 10,846
  • 1
  • 25
  • 34
  • 1
    Great, it works! Took me several hours though to figure out that the index needs about a second after definition to be available to a direct index query; Thus automatic tests kept failing to find expected nodes. May I suggest adding this as a note to your answer? Thanks for introducing me to this kind of queries. – Double M Jan 18 '18 at 12:46
  • If the index the query is executed on is restricted to a set of vertex labels, only results with such labels will be returned, right? – Double M Feb 25 '18 at 14:11
  • 1
    Obviously yes, the index will not contain any data of other vertices. – Daniel Kuppitz Feb 26 '18 at 15:11