Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents


Goals

  1. User can specified fields in nested object to be indexed. 

  2. Query on these nested fields as well as top level fields. 

...


2.  When querying, the syntax of nested field is the same as toplevel field, i.e. without parent field's name. For example: "email:tzhou12*". 

In order to to find the parent document using the child object's field or grandchild object's field (such as use contact's email to find the customer), we need to use lucene's Join package. Geode provides 

LuceneQueryProvider interface to implement such a query. 

 

Code Block
package org.apache.geode.cache.lucene;

public interface LuceneQueryProvider extends Serializable {

  /**
   * @return A {@link Query} which will be executed against a Lucene index.
   * @param index The {@link LuceneIndex} the query is being executed against.
   * @throws LuceneQueryException if the provider fails to construct the query object. This will be
   *         propagated to callers of the {@link LuceneQuery} find methods.
   */
  Createpublic Query with nested objects
 getQuery(LuceneIndex index) throws LuceneQueryException;
}


There're several ways in lucene's Join package to search on nested object. https://lucene.apache.org/core/6_3_0/join/org/apache/lucene/search/join/package-summary.html

Such as , such as ToParentBlockJoinQuery, ToChildBlockJoinQuery, JoinUtil. 

In this spec, we provided 2 examples of LuceneQueryProvider implementation using ToParentBlockJoinQuery, one for parent-child join, another for grandparent-parent-child join. 

 

Code Block
// Example of parent-child join using ToParentBlockJoinQuery
public class ToParentBlockJoinQueryProvider implements LuceneQueryProvider {
  String parentFilterField;
  String parentFilterString;
  String queryOnChild;
  String defaultFieldOnChild;
  
  private transient Query luceneQuery;

  public ToParentBlockJoinQueryProvider(String parentFilterField, String parentFilterString, String queryOnChild, 
      String defaultFieldOnChild) {
    this.parentFilterField = parentFilterField;
    this.parentFilterString = parentFilterString;
    this.queryOnChild = queryOnChild;
    this.defaultFieldOnChild = defaultFieldOnChild;
  }

  @Override
  public Query getQuery(LuceneIndex index) throws LuceneQueryException {
    if (luceneQuery == null) {
      final StandardQueryParser queryParser = new StandardQueryParser(new KeywordAnalyzer());
LuceneQuery query;
      Query childQuery = null;
      try {
        childQuery = luceneServicequeryParser.createLuceneQueryFactoryparse().setLimit(200).setPageSize(20)
  .create(indexName, regionName, querystring, "field1" /* default field */);

queryOnChild, defaultFieldOnChild);
      }
      catch (QueryNodeException e) {
      }

      BitSetProducer parentFilter = new QueryBitSetProducer(new WildcardQuery(new Term(parentFilterField, parentFilterString)));
      luceneQuery = new ToParentBlockJoinQuery(childQuery, parentFilter, ScoreMode.Total);
    }

    return luceneQuery;
  }
}
 
 
// Search using Query
PageableLuceneQueryResults<K,Object> results = query.findPages();

// Pagination
while (results.hasNext()) {
  results.next().stream().forEach(struct -> {
    Object value = struct.getValue();
    System.out.println("Key is "+struct.getKey()+", value is "+value);
  });
} with nested object using the above LuceneQueryProvider
// It will search child's field "email" for "tzhou11*" and return all the matched parent object, i.e. Customer object
// The parent filter "*" will return all the matched parent object in this example.
ToParentBlockJoinQueryProvider provider = new ToParentBlockJoinQueryProvider("symbol" /*parentField*/, "*" /*parentFilter*/, 
  "email:tzhou11*" /*childQueryString*/, "email" /*childField*/);
LuceneQuery query = luceneService.createLuceneQueryFactory().create("customerIndex", "Customer", provider);
 
PageableLuceneQueryResults<K,Object> results = query.findPages();