Versions Compared

Key

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

...

Code Block
/**
 * Create a lucene index using default analyzer.
 * @param luceneSerializer A callback which converts a region value to a 
 * Lucene document or documents to be stored in the index.
 */
public void createIndex(String indexName, String regionPath, LuceneSerializer luceneSerializer);

 
 
 
/**
 * An interface for writing the fields of an object into a lucene document
 * The region key will be added as a field to the returned documents.
 */
public interface LuceneSerializer {

  // The nested object (value) will be saved as a group of documents, in the order of 
  // child document1, child document2, parent document
  Collection<Document> toDocuments(Object value);
}

...

Code Block
// Get LuceneService
LuceneService luceneService = LuceneServiceProvider.get(cache);

// Create Index on fields, some are fields in nested objects:
luceneService.createIndexFactory().setLuceneSerializer(new NestedObjectSeralizer()) /* an out-of-box LuceneSerializer implementation */
      .addField("name").addField("symbol").addField("revenue").addField("SSN")
      .addField("contact.name").addField("contact.email").addField("contact.address").addField("contact.homepage.title")
      .create("customerIndex", "Customer");

// Now to create region
Region CustomerRegion = ((Cache)cache).createRegionFactory(shortcut).create("Customer");


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

In order 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.
   */
  public Query getQuery(LuceneIndex index) throws LuceneQueryException;
}

...

top level field, but to use qualified name as the field name, such as "customer.email:2.  

Code Block
LuceneQuery query = luceneService.createLuceneQueryFactory().create("customerIndex", "Customer", "contact.email:tzhou11*", "name"

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());
      Query childQuery = null;
      try {
        childQuery = queryParser.parse(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 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();

 

Index solution and document format in the Out-Of-Box implementation

We'll provide an out-of-box implementation for the LuceneSerializer.