Versions Compared

Key

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

...

  1. A single index will not support multiple regions. Join queries between regions are not supported

  2. Heterogeneous objects in single region will be supported
  3. Only top level fields and of nested objects can be indexed, not nested collections
  4. The index needs to be created before the region is created (for phase1) 
  5. Pagination of results will be supported

...

  

LuceneQueryFactory

Code Block
 /**
   * Set page size for a query result. The default page size is 0 which means no pagination.
   * If specified negative value, throw IllegalArgumentException
   * @param pageSize
   * @return itself
   */
  LuceneQueryFactory setPageSize(int pageSize);
  
  /**
   * Set max limit of result for a query
   * If specified limit is less or equal to zero, throw IllegalArgumentException
   * @param limit
   * @return itself
   */
  LuceneQueryFactory setResultLimit(int limit);
  
  /**
   * Set a list of fields for result projection.
   * 
   * @param fieldNames
   * @return itself
   */
  LuceneQueryFactory setProjectionFields(String... fieldNames);
  
  /**
   * Create wrapper object for lucene's QueryParser object using default standard analyzer.
   * The queryString is using lucene QueryParser's syntax. QueryParser is for easy-to-use 
   * with human understandable syntax. 
   *  
   * @param regionName region name
   * @param indexName index name
   * @param queryString query string in lucene QueryParser's syntax
   * @param K the key type in the query results
   * @param V the value type in the query results
   * @return LuceneQuery object
   * @throws ParseException
   */
  public <K, V> LuceneQuery<K, V> create(String indexName, String regionName, String queryString) 
      throws ParseException;
  /**
   * Creates a wrapper object for Lucene's Query object. This {@link LuceneQuery} builder method could be used in
   * advanced cases, such as cases where Lucene's Query object construction needs Lucene's API over query string. The
   * {@link QueryDeserializer} will be used to re-construct the Lucene Query object on remote hosts.
   * 
   * @param indexName index name
   * @param regionName region name
   * @param provider constructs and provides a Lucene Query object
   * @param K the key type in the query results
   * @param V the value type in the query results
   * @return LuceneQuery object
   */
  public <K, V> LuceneQuery<K, V> create(String indexName, String regionName, LuceneQueryProvider provider);

/**
 * The instances of this class will be used for distributing Lucene Query objects and re-constructing the Query object.
 * If necessary the implementation needs to take care of serializing and de-serializing Lucene Query object. Geode
 * respects the DataSerializable contract to provide optimal object serialization. For instance,
 * {@link LuceneQueryProvider}'s toData method will be used to serialize it when it is sent to another member of the
 * distributed system. Implementation of DataSerializable can provide a zero-argument constructor that will be invoked
 * when they are read with DataSerializer.readObject.
 */
public interface LuceneQueryProvider extends Serializable {
  /**
   * @return A Lucene Query object which could be used for executing Lucene Search on indexed data
   * @param The local lucene index the query is being constructed against.
   * @throws QueryException if the provider fails to construct the query object
   */
  public Query getQuery(LuceneIndex index) throws QueryException;
}

LuceneQuery

Code Block
/**
 * Provides wrapper object of Lucene's Query object and execute the search. 
 * <p>Instances of this interface are created using
 * {@link LuceneQueryFactory#create}.
 * 
 */
public interface LuceneQuery {
  /**
   * Execute the search and getreturn resultskeys. 
   */
  public LuceneQueryResults<?>Collection<K> searchfindKeys();
  
  /**
   * GetExecute pagethe sizesearch settingand ofreturn current queryvalues. 
   */
  public intCollection<V> getPageSizefindValues();
  
  /**
   * Execute Getthe search limitand sizereturn settinglist of current queryLuceneResultStruct. 
   */
  public intList<LuceneResultStruct<K,V>> getLimitfindResults();
  
  /**
   * GetExecute projectedthe fieldssearch settingand ofget current queryresults. 
   */
  public String[] getProjectedFieldNamesPageableLuceneQueryResults<K,V> findPages();
}
 

LuceneResultStruct

Code Block
  
  /**
   * ReturnGet thepage valuesize associatedsetting withof thecurrent givenquery. field name
   */
  public * @param fieldName the String name of the fieldint getPageSize();
  
  /**
   * @returnGet thelimit valuesize associatedsetting withof thecurrent specifiedquery. field
   */
 @throws IllegalArgumentExceptionpublic If this struct does not have a field named fieldNameint getLimit();
  
  /**
   * Get projected fields setting of current query. 
   */
  public ObjectString[] getProjectedFieldgetProjectedFieldNames(String fieldName);
}
 

LuceneResultStruct

Code Block
  
  /**
   * Return the value keyassociated ofwith the given entryfield name
   *
   * @return@param key
fieldName the String *name @throwsof IllegalArgumentException the field
   * @return the value associated with the specified field
   * @throws IllegalArgumentException If this struct does not contain key have a field named fieldName
   */
  public Object getKeygetProjectedField(String fieldName);
  
  /**
   * Return valuekey of the entry
   *
   * @return value the whole domain objectkey
   * @throws IllegalArgumentException If this struct does not contain valuekey
   */
  public Object getValuegetKey();
  
  /**
   * Return scorevalue of the query entry
   *
   * @return score value the whole domain object
   * @throws IllegalArgumentException If this struct does not contain scorevalue
   */
  public DoubleObject getScoregetValue();
  
   
  /**
   * Return score Getof the query 
 values  in*
 same order as* result@return typesscore
   * @return the array of values @throws IllegalArgumentException If this struct does not contain score
   */
  public Object[]Double getResultValuesgetScore();
  
}

    Examples

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

// Create Index on fields with default analyzer:
luceneService.createIndex(indexName, regionName, "field1", "field2", "field3");

// create index on fields with specified analyzer:
luceneService.createIndex(indexName, regionName, analyzerPerField);

// Map<String, Analyzer> analyzerPerField = new HashMap<String, Analyzer>();
analyzerPerfield.put("field1", new StandardAnalyzer());
analyzerPerfield.put("field2", new KeywardAnalyzer());
luceneService.createIndex(indexName, regionName, analyzerPerField);
 
Region region = cache.createRegionFactory(RegionShutcut.PARTITION).create(regionName);

// Create Query
LuceneQuery query = luceneService.createLuceneQueryFactory().setLimit(200).setPageSize(20)
  .setFieldProjection("field1", "field2")
  .create(indexName, regionName, querystring, analyzer);

// Search using Query
LuceneQueryResults results = query.search();

List values = results.getNextPage(); // return all results in one page "field1" /* default field */);

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

// Pagination
while (results.hasNextPagehasNext()) {
  List page = results.next().getNextPagestream(); // return result page by page

  for (LuceneResultStruct r : page) {.forEach(struct -> {
    Object value = struct.getValue();
    System.out.println(r.getValue()"Key is "+struct.getKey()+", value is "+value);
  });
}

 

Gfsh API (Not Yet Implemented)

 

Code Block
// CreateList Index
gfsh> createlist lucene indexindexes --name=indexName --region=/orders --field=customer,tags
or[with-stats]
// Create Index
gfsh> create lucene index --name=indexName --region=/orders --field=customer --field=,tags

// Create Index
gfsh> create lucene index --name=indexName --region=/orders --field=customer,tags --analyzer=org.apache.lucene.analysis.standard.StandardAnalyzer,org.apache.lucene.analysis.bg.BulgarianAnalyzer

// Destory Index
gfsh> destroy lucene index --name=indexName --region=/orders

Execute Lucene query
gfsh> search lucene search --regionName=/orders -queryStrings="John*" --defaultField=field1 --limit=100

 

XML Configuration 

 

Code Block
<cache
    xmlns="http://geode.apache.org/schema/cache"
    xmlns:lucene="http://geode.apache.org/schema/lucene"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://geode.apache.org/schema/cache
        http://geode.apache.org/schema/cache/cache-1.0.xsd
        http://geode.apache.org/schema/lucene
        http://geode.apache.org/schema/lucene/lucene-1.0.xsd"
    version="1.0">

    <region name="region" refid="PARTITION">
        <lucene:index name="index">
          <lucene:field name="a" analyzer="org.apache.lucene.analysis.core.KeywordAnalyzer"/>
          <lucene:field name="b" analyzer="org.apache.lucene.analysis.core.SimpleAnalyzer"/>
          <lucene:field name="c" analyzer="org.apache.lucene.analysis.standard.ClassicAnalyzer"/>
        </lucene:index>
    </region>
</cache>

 

REST API

TBD - But using solr to provide a REST API might make a lot of sense

Spring Data GemFire Support

TBD - But the Searchable annotation described in this blog might be a good place to start.

Implementation Flowchart

 

...