geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From zho...@apache.org
Subject [geode] branch feature/GEODE-3244 updated: GEODE-3244: provide a build in LuceneSerializer that flattens objects
Date Thu, 05 Oct 2017 22:03:18 GMT
This is an automated email from the ASF dual-hosted git repository.

zhouxj pushed a commit to branch feature/GEODE-3244
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/feature/GEODE-3244 by this push:
     new 3153672  GEODE-3244: provide a build in LuceneSerializer that flattens objects
3153672 is described below

commit 315367200548f6bd0816c819897af09a74873b00
Author: zhouxh <gzhou@pivotal.io>
AuthorDate: Thu Oct 5 15:01:59 2017 -0700

    GEODE-3244: provide a build in LuceneSerializer that flattens objects
---
 .../geode/cache/lucene/LuceneSerializer.java       |   1 +
 .../repository/serializer/FieldsWithPrefix.java}   |  35 ++-
 .../serializer/FlatFormatSerializer.java           | 295 +++++++++++++++++++++
 .../serializer/ReflectionLuceneSerializer.java     |  10 +-
 .../NestedObjectSeralizerIntegrationTest.java      | 130 +++++++++
 .../apache/geode/cache/lucene/test/Customer.java}  |  35 ++-
 .../org/apache/geode/cache/lucene/test/Page.java}  |  41 +--
 .../apache/geode/cache/lucene/test/Person.java}    |  43 +--
 8 files changed, 508 insertions(+), 82 deletions(-)

diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
index 363867d..ceebc65 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
@@ -32,6 +32,7 @@ public interface LuceneSerializer extends Declarable {
    * Add the fields of the given value to a set of documents
    * 
    * @param index lucene index
+   * @param value user object to be serialized into index
    */
   Collection<Document> toDocuments(LuceneIndex index, Object value);
 }
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/FieldsWithPrefix.java
similarity index 59%
copy from geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
copy to geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/FieldsWithPrefix.java
index 363867d..cc40439 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/FieldsWithPrefix.java
@@ -4,34 +4,29 @@
  * copyright ownership. The ASF licenses this file to you under the Apache License, Version
2.0 (the
  * "License"); you may not use this file except in compliance with the License. You may obtain
a
  * copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under
the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express
  * or implied. See the License for the specific language governing permissions and limitations
under
  * the License.
  */
+package org.apache.geode.cache.lucene.internal.repository.serializer;
 
-package org.apache.geode.cache.lucene;
+import java.util.HashSet;
 
-import java.util.Collection;
+public class FieldsWithPrefix {
+  HashSet<String> topLevelFieldSet;
+  String prefix;
 
-import org.apache.geode.cache.Declarable;
-import org.apache.lucene.document.Document;
+  FieldsWithPrefix(HashSet<String> topLevelFieldSet, String prefix) {
+    this.topLevelFieldSet = topLevelFieldSet;
+    this.prefix = prefix;
+  }
 
-import org.apache.geode.annotations.Experimental;
-
-/**
- * An interface for writing the fields of an object into a lucene document
- */
-@Experimental
-public interface LuceneSerializer extends Declarable {
-
-  /**
-   * Add the fields of the given value to a set of documents
-   * 
-   * @param index lucene index
-   */
-  Collection<Document> toDocuments(LuceneIndex index, Object value);
+  @Override
+  public String toString() {
+    return "prefix is " + prefix + ", topLevelFieldSet is " + topLevelFieldSet;
+  }
 }
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/FlatFormatSerializer.java
b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/FlatFormatSerializer.java
new file mode 100644
index 0000000..f3bb5bd
--- /dev/null
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/FlatFormatSerializer.java
@@ -0,0 +1,295 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information
regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version
2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain
a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express
+ * or implied. See the License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package org.apache.geode.cache.lucene.internal.repository.serializer;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.apache.geode.cache.lucene.LuceneIndex;
+import org.apache.geode.cache.lucene.LuceneSerializer;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.util.concurrent.CopyOnWriteWeakHashMap;
+import org.apache.geode.pdx.PdxInstance;
+import org.apache.logging.log4j.Logger;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field.Store;
+import org.apache.lucene.document.FieldType;
+import org.apache.lucene.document.LongPoint;
+import org.apache.lucene.document.TextField;
+import org.apache.lucene.index.IndexableField;
+
+public class FlatFormatSerializer implements LuceneSerializer {
+  /**
+   * A mapper for converting a PDX object into a document
+   */
+  private LuceneSerializer pdxMapper;
+
+  /**
+   * Mappers for each individual class type that this class has seen.
+   * 
+   * Weak so that entry will be removed if a class is garbage collected.
+   */
+  private Map<Class<?>, LuceneSerializer> mappers =
+      new CopyOnWriteWeakHashMap<Class<?>, LuceneSerializer>();
+
+  /**
+   * keep class to defined fields mapping for each class For example, Customer object based
on
+   * indexed fields name, contact.name, contact.address, contact.homepage.title will become
+   * <Customer.class, (<name, contact>, prefix=null)>; <Person.class, (<name,
address,
+   * homepage.title>, prefix=contact)>, <Page.class, (<title>, prefix=contact.homepage)>
+   */
+  public HashMap<Class<?>, FieldsWithPrefix> classToFieldsMapping = new HashMap();
+
+  private static final Logger logger = LogService.getLogger();
+
+  public FlatFormatSerializer() {
+    final PrimitiveSerializer primitiveSerializer = new PrimitiveSerializer();
+    SerializerUtil.supportedPrimitiveTypes().stream()
+        .forEach(type -> mappers.put(type, primitiveSerializer));
+
+    pdxMapper = new PdxLuceneSerializer();
+  }
+
+  @Override
+  public Collection<Document> toDocuments(LuceneIndex index, Object value) {
+    if (value == null) {
+      return Collections.emptyList();
+    }
+
+    LuceneSerializer mapper = getFieldMapper(value, index.getFieldNames());
+
+    Collection<Document> docs = mapper.toDocuments(index, value);
+    if (logger.isDebugEnabled()) {
+      logger.debug("FlatFormatSerializer.toDocuments:" + docs);
+    }
+
+    return docs;
+  }
+
+  /**
+   * Get the field mapper based on the type of the given object.
+   */
+  public LuceneSerializer getFieldMapper(Object value, String[] indexedFields) {
+    if (value instanceof PdxInstance) {
+      return FlatFormatSerializer.this.pdxMapper;
+    } else {
+      Class<?> clazz = value.getClass();
+      LuceneSerializer mapper = null;
+      synchronized (mappers) {
+        mapper = mappers.get(clazz);
+        if (mapper == null) {
+          // parse this nested object (i.e. customerObject) to build class-fields map for
each field
+          // At this time, the parameters are (customerObject, <name, contact.name, contact.address,
+          // contact.homepage.title>)
+          // create classToFields mapping for value's class
+          // finally classToFieldsMapping will contain:
+          // <Customer.class, <name, contact>>, <Person.class, <name, address,
homepage>>,
+          // <Page.class, <title>>
+          createClassToFieldsMapping(value, indexedFields, null);
+
+          // search in current mappers for all the classes used in this nested object
+          for (Map.Entry<Class<?>, FieldsWithPrefix> entry : classToFieldsMapping.entrySet())
{
+            Class<?> aClassWithIndexedFields = entry.getKey();
+            if (mappers.get(aClassWithIndexedFields) == null) {
+              // if the class is still not in mappers, and it contains non-nested fields,
just
+              // create
+              // ReflectionLuceneSerializer
+              HashSet<String> topLevelFieldSet = entry.getValue().topLevelFieldSet;
+              String prefix = entry.getValue().prefix;
+              String[] fields = topLevelFieldSet.toArray(new String[topLevelFieldSet.size()]);
+
+              // parameters are (Customer.class, <name, contact>)
+              mapper =
+                  new FlatFormatReflectionLuceneSerializer(aClassWithIndexedFields, fields,
prefix);
+              mappers.put(aClassWithIndexedFields, mapper);
+            }
+          }
+          return mappers.get(clazz);
+        } else {
+          return mapper;
+        }
+      }
+    }
+  }
+
+  /*
+   * create value's class to its indexed fields mapping
+   */
+  private void createClassToFieldsMapping(Object value, String[] indexedFields, String prefix)
{
+    Class<?> clazz = value.getClass();
+    FieldsWithPrefix fieldsWithPrefix = classToFieldsMapping.get(clazz);
+    if (fieldsWithPrefix == null) {
+      HashSet<String> topLevelFieldSet = new HashSet<String>();
+      fieldsWithPrefix = new FieldsWithPrefix(topLevelFieldSet, prefix);
+      classToFieldsMapping.put(clazz, fieldsWithPrefix);
+    } else {
+      return;
+    }
+    if (logger.isDebugEnabled()) {
+      logger.debug("createClassToFieldsMapping:found an undefined class, object value is
" + value
+          + ":indexedFields are " + Arrays.toString(indexedFields) + ", prefix is " + prefix);
+    }
+
+    // parent field (e.g. contact) to child fields is a 1:N mapping,
+    // such as contact to <name, address, homepage.title>
+    HashMap<String, HashSet<String>> parentToChildFieldsMapping = new HashMap();
+    for (String f : indexedFields) {
+      int firstDot = f.indexOf(".");
+      if (firstDot != -1) {
+        // found a parent-child field
+        String parentFieldName = f.substring(0, firstDot);
+        String childFieldName = f.substring(firstDot + 1);
+        HashSet<String> childFieldSet = parentToChildFieldsMapping.get(parentFieldName);
+        if (childFieldSet == null) {
+          childFieldSet = new HashSet<String>();
+          parentToChildFieldsMapping.put(parentFieldName, childFieldSet);
+        }
+        childFieldSet.add(childFieldName);
+
+        fieldsWithPrefix.topLevelFieldSet.add(parentFieldName);
+      } else {
+        // only found a top level field
+        fieldsWithPrefix.topLevelFieldSet.add(f);
+      }
+    }
+    if (logger.isDebugEnabled()) {
+      logger.info("createClassToFieldsMapping:topLevelFieldSet is "
+          + fieldsWithPrefix.topLevelFieldSet + ":prefix is " + prefix
+          + ":parentToChildFieldsMap is " + parentToChildFieldsMapping);
+    }
+
+    // Now we've got a topLevelFieldSet, such as <name, contact> and a parentToChildFieldsMapping
+    // such as <contact, <name, address, homepage.title>>
+    // for each parent field, i.e. contact, recursively process with its childFieldSet, i.e.
<name,
+    // address, homepage.title>
+    for (Map.Entry<String, HashSet<String>> entry : parentToChildFieldsMapping.entrySet())
{
+      try {
+        String parentFieldName = entry.getKey();
+        HashSet<String> childFieldSet = entry.getValue();
+        String[] childFields = childFieldSet.toArray(new String[childFieldSet.size()]);
+
+        // parentFieldName is to get childValue
+        Object childValue = getFieldValue(value, parentFieldName);
+
+        // now we've got a child object, find class-fields mapping for its fields
+        // this time, the parameters are (personObject, <name, address, homepage.title>)
+        createClassToFieldsMapping(childValue, childFields, parentFieldName);
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  private Object getFieldValue(Object parentValue, String parentFieldName)
+      throws NoSuchFieldException, SecurityException {
+    // now check if there's grandchild in nestedFields
+    Class<?> parentClazz = parentValue.getClass();
+    Field field = parentClazz.getDeclaredField(parentFieldName);
+    Object childValue = null;
+    try {
+      field.setAccessible(true);
+      childValue = field.get(parentValue);
+    } catch (Exception e) {
+      e.printStackTrace(System.out);
+    }
+    return childValue;
+  }
+
+  class FlatFormatReflectionLuceneSerializer extends ReflectionLuceneSerializer {
+
+    String prefix;
+
+    public FlatFormatReflectionLuceneSerializer(Class<? extends Object> clazz,
+        String[] indexedFields, String prefix) {
+      super(clazz, indexedFields);
+      this.prefix = prefix;
+    }
+
+    @Override
+    public Collection<Document> toDocuments(LuceneIndex index, Object value) {
+      Document parentDoc = new Document();
+
+      for (Field field : fields) {
+        try {
+          field.setAccessible(true);
+          Object fieldValue = field.get(value);
+          if (fieldValue == null) {
+            continue;
+          }
+          Class<?> fieldType = field.getType();
+
+          if (classToFieldsMapping.containsKey(fieldType)) {
+            // for each object field value with class defined in classToFieldsMapping, serialize
it
+            // to a document
+            // then add the document's indexableFields into parentDoc
+            FieldsWithPrefix fieldsWithPrefix = classToFieldsMapping.get(fieldType);
+            HashSet<String> topLevelFieldSet = fieldsWithPrefix.topLevelFieldSet;
+            String[] topLevelFieldNames =
+                topLevelFieldSet.toArray(new String[topLevelFieldSet.size()]);
+
+            LuceneSerializer childSerializer = getFieldMapper(fieldValue, topLevelFieldNames);
+            Collection<Document> childDocs = childSerializer.toDocuments(index, fieldValue);
+            for (Document childDoc : childDocs) {
+              for (IndexableField oneDocField : childDoc.getFields()) {
+                parentDoc.add(addPrefixToDocumentField(oneDocField, prefix));
+              }
+            }
+          } else {
+            SerializerUtil.addField(parentDoc,
+                (prefix == null ? field.getName() : prefix + "." + field.getName()), fieldValue);
+          }
+        } catch (IllegalArgumentException | IllegalAccessException e) {
+          if (logger.isDebugEnabled()) {
+            logger.debug("FlatFormatReflectionLuceneSerializer.toDocuments encountered exception",
+                e);
+          }
+        }
+      }
+      if (logger.isDebugEnabled()) {
+        logger.debug("FlatFormatReflectionLuceneSerializer.toDocuments:" + parentDoc);
+      }
+      return Collections.singleton(parentDoc);
+    }
+
+    private IndexableField addPrefixToDocumentField(IndexableField oneDocField, String prefix)
{
+      if (prefix == null) {
+        return oneDocField;
+      }
+      String newName = prefix + "." + oneDocField.name();
+      //      // do it for each field type used in SerializerUtil.addField()
+      if (oneDocField instanceof TextField) {
+        TextField newTextField = new TextField(newName, ((TextField)oneDocField).stringValue(),
Store.NO);
+        return newTextField;
+      }
+      // TODO: we have to change field name for each field type. But LongPoint seems not
straightforward.
+      return null;
+    }
+
+    protected boolean isSupported(Class<?> type) {
+      return true;
+    }
+
+    @Override
+    public String toString() {
+      return "FlatFormatReflectionLuceneSerializer:prefix is " + prefix + ", fields are "
+          + Arrays.toString(fields);
+    }
+  }
+}
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/ReflectionLuceneSerializer.java
b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/ReflectionLuceneSerializer.java
index 5b9298b..176d4e1 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/ReflectionLuceneSerializer.java
+++ b/geode-lucene/src/main/java/org/apache/geode/cache/lucene/internal/repository/serializer/ReflectionLuceneSerializer.java
@@ -35,9 +35,9 @@ import org.apache.geode.internal.logging.LogService;
  */
 class ReflectionLuceneSerializer implements LuceneSerializer {
 
-  private Field[] fields;
+  protected Field[] fields;
 
-  private static final Logger logger = LogService.getLogger();
+  protected static final Logger logger = LogService.getLogger();
 
   public ReflectionLuceneSerializer(Class<? extends Object> clazz, String[] indexedFields)
{
     Set<String> fieldSet = new HashSet<String>();
@@ -50,7 +50,7 @@ class ReflectionLuceneSerializer implements LuceneSerializer {
     while (clazz != Object.class) {
       for (Field field : clazz.getDeclaredFields()) {
         Class<?> type = field.getType();
-        if (fieldSet.contains(field.getName()) && SerializerUtil.isSupported(type))
{
+        if (fieldSet.contains(field.getName()) && isSupported(type)) {
           field.setAccessible(true);
           foundFields.add(field);
         }
@@ -62,6 +62,10 @@ class ReflectionLuceneSerializer implements LuceneSerializer {
     this.fields = foundFields.toArray(new Field[foundFields.size()]);
   }
 
+  protected boolean isSupported(Class<?> type) {
+    return SerializerUtil.isSupported(type);
+  }
+
   @Override
   public Collection<Document> toDocuments(LuceneIndex index, Object value) {
     Document doc = new Document();
diff --git a/geode-lucene/src/test/java/org/apache/geode/cache/lucene/NestedObjectSeralizerIntegrationTest.java
b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/NestedObjectSeralizerIntegrationTest.java
new file mode 100644
index 0000000..b855d4f
--- /dev/null
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/NestedObjectSeralizerIntegrationTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information
regarding
+ * copyright ownership. The ASF licenses this file to you under the Apache License, Version
2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain
a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under
the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express
+ * or implied. See the License for the specific language governing permissions and limitations
under
+ * the License.
+ */
+package org.apache.geode.cache.lucene;
+
+import static org.apache.geode.cache.lucene.test.LuceneTestUtilities.INDEX_NAME;
+import static org.apache.geode.cache.lucene.test.LuceneTestUtilities.REGION_NAME;
+import static org.junit.Assert.assertEquals;
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.cache.lucene.internal.repository.serializer.FlatFormatSerializer;
+import org.apache.geode.cache.lucene.test.Customer;
+import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.apache.lucene.analysis.core.KeywordAnalyzer;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+@Category(IntegrationTest.class)
+public class NestedObjectSeralizerIntegrationTest extends LuceneIntegrationTest {
+
+  private static int WAIT_FOR_FLUSH_TIME = 10000;
+  private static final Logger logger = LogService.getLogger();
+
+  @Test
+  public void queryOnNestedObject() throws InterruptedException, LuceneQueryException {
+    // define index on nested objects
+    luceneService.createIndexFactory().setLuceneSerializer(new FlatFormatSerializer())
+        .addField("name").addField("contact.name").addField("contact.email", new KeywordAnalyzer())
+        .addField("contact.address").addField("contact.homepage.content")
+        .create(INDEX_NAME, REGION_NAME);
+
+    Region region = createRegion(REGION_NAME, RegionShortcut.PARTITION);
+
+    // insert a few records
+    region.put("object-13", new Customer("Tommy Jaskcon"));
+    region.put("object-14", new Customer("Johnny Jackson"));
+    region.put("object-15", new Customer("Johnny Jackson2"));
+    region.put("object-16", new Customer("Johnny Jackson21"));
+
+    LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME);
+    luceneService.waitUntilFlushed(INDEX_NAME, REGION_NAME, WAIT_FOR_FLUSH_TIME,
+        TimeUnit.MILLISECONDS);
+
+    // query-1: contact.name
+    LuceneQuery query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "contact.name:jackson2*", "name");
+    PageableLuceneQueryResults<Integer, Customer> results = query.findPages();
+    assertEquals(2, results.size());
+
+    // query-2: name
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "\"Johnni Jackson\"", "contact.name");
+    results = query.findPages();
+    assertEquals(1, results.size());
+    printResults(results);
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "\"Johnni Jackson\"", "name");
+    results = query.findPages();
+    printResults(results);
+    assertEquals(0, results.size());
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "\"Johnny Jackson\"", "name");
+    results = query.findPages();
+    assertEquals(1, results.size());
+    printResults(results);
+
+    // query-3: contact.email with KeywordAnalyzer
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "Johnni.Jackson2@pivotal.io", "contact.email");
+    results = query.findPages();
+    assertEquals(1, results.size());
+    printResults(results);
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "Johnni.Jackson2@pivotal.io", "email");
+    results = query.findPages();
+    printResults(results);
+    assertEquals(0, results.size());
+
+    // query-4: contact.address with standard analyzer
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME, "97006",
+        "contact.address");
+    results = query.findPages();
+    assertEquals(4, results.size());
+    printResults(results);
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME, "97006",
+        "address");
+    results = query.findPages();
+    printResults(results);
+    assertEquals(0, results.size());
+
+    // query-4: contact.homepage.title
+    query = luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME,
+        "contact.homepage.content:Hello", "name");
+    results = query.findPages();
+    printResults(results);
+    assertEquals(4, results.size());
+    query =
+        luceneService.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME, "Hello",
"title");
+    results = query.findPages();
+    printResults(results);
+    assertEquals(0, results.size());
+  }
+
+  private void printResults(PageableLuceneQueryResults<Integer, Customer> results)
{
+    if (results.size() > 0) {
+      while (results.hasNext()) {
+        results.next().stream().forEach(struct -> {
+          logger.info("Result is:" + struct.getValue());
+        });
+      }
+    }
+  }
+
+}
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Customer.java
similarity index 59%
copy from geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
copy to geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Customer.java
index 363867d..440e0d7 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Customer.java
@@ -4,34 +4,31 @@
  * copyright ownership. The ASF licenses this file to you under the Apache License, Version
2.0 (the
  * "License"); you may not use this file except in compliance with the License. You may obtain
a
  * copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under
the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express
  * or implied. See the License for the specific language governing permissions and limitations
under
  * the License.
  */
+package org.apache.geode.cache.lucene.test;
 
-package org.apache.geode.cache.lucene;
+import java.io.Serializable;
 
-import java.util.Collection;
+public class Customer implements Serializable {
+  private String name;
+  private Person contact; // search nested object
 
-import org.apache.geode.cache.Declarable;
-import org.apache.lucene.document.Document;
+  public Customer(String name) {
+    this.name = name;
 
-import org.apache.geode.annotations.Experimental;
+    // purposely use Tommi instead of Tommy, Johnni instead of Johnny in contact.name
+    this.contact = new Person(name.replace('y', 'i'));
+  }
 
-/**
- * An interface for writing the fields of an object into a lucene document
- */
-@Experimental
-public interface LuceneSerializer extends Declarable {
-
-  /**
-   * Add the fields of the given value to a set of documents
-   * 
-   * @param index lucene index
-   */
-  Collection<Document> toDocuments(LuceneIndex index, Object value);
+  @Override
+  public String toString() {
+    return "Customer[name=" + name + ",contact=" + contact + "]";
+  }
 }
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Page.java
similarity index 59%
copy from geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
copy to geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Page.java
index 363867d..bd0dc57 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Page.java
@@ -4,34 +4,35 @@
  * copyright ownership. The ASF licenses this file to you under the Apache License, Version
2.0 (the
  * "License"); you may not use this file except in compliance with the License. You may obtain
a
  * copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under
the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express
  * or implied. See the License for the specific language governing permissions and limitations
under
  * the License.
  */
+package org.apache.geode.cache.lucene.test;
 
-package org.apache.geode.cache.lucene;
+import java.io.Serializable;
 
-import java.util.Collection;
+public class Page implements Serializable {
+  private int id;
+  private String title;
+  private String content;
 
-import org.apache.geode.cache.Declarable;
-import org.apache.lucene.document.Document;
+  public Page(int id) {
+    this.id = id;
+    if (id % 2 == 0) {
+      this.title = "manager";
+    } else {
+      this.title = "developer";
+    }
+    this.content = "Hello world no " + id;
+  }
 
-import org.apache.geode.annotations.Experimental;
-
-/**
- * An interface for writing the fields of an object into a lucene document
- */
-@Experimental
-public interface LuceneSerializer extends Declarable {
-
-  /**
-   * Add the fields of the given value to a set of documents
-   * 
-   * @param index lucene index
-   */
-  Collection<Document> toDocuments(LuceneIndex index, Object value);
+  @Override
+  public String toString() {
+    return "Page[id=" + id + ",title=" + title + ",content=" + content + "]";
+  }
 }
diff --git a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Person.java
similarity index 52%
copy from geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
copy to geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Person.java
index 363867d..dc7b1cf 100644
--- a/geode-lucene/src/main/java/org/apache/geode/cache/lucene/LuceneSerializer.java
+++ b/geode-lucene/src/test/java/org/apache/geode/cache/lucene/test/Person.java
@@ -4,34 +4,37 @@
  * copyright ownership. The ASF licenses this file to you under the Apache License, Version
2.0 (the
  * "License"); you may not use this file except in compliance with the License. You may obtain
a
  * copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software distributed under
the License
  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
express
  * or implied. See the License for the specific language governing permissions and limitations
under
  * the License.
  */
+package org.apache.geode.cache.lucene.test;
 
-package org.apache.geode.cache.lucene;
+import java.io.Serializable;
 
-import java.util.Collection;
+public class Person implements Serializable {
+  private String name;
+  private String email;
+  private int revenue;
+  private String address;
+  private Page homepage;
 
-import org.apache.geode.cache.Declarable;
-import org.apache.lucene.document.Document;
+  public Person(String name) {
+    this.name = name;
+    this.email = name.replace(' ', '.') + "@pivotal.io";
+    int length = name.length();
+    this.revenue = length * 100;
+    this.address = "" + length + " NW Greenbrier PKWY, Portland OR 97006";
+    this.homepage = new Page(length);
+  }
 
-import org.apache.geode.annotations.Experimental;
-
-/**
- * An interface for writing the fields of an object into a lucene document
- */
-@Experimental
-public interface LuceneSerializer extends Declarable {
-
-  /**
-   * Add the fields of the given value to a set of documents
-   * 
-   * @param index lucene index
-   */
-  Collection<Document> toDocuments(LuceneIndex index, Object value);
+  @Override
+  public String toString() {
+    return "Person[name=" + name + ",email=" + email + ",revenue=" + revenue + ",address="
+ address
+        + ",homepage=" + homepage + "]";
+  }
 }

-- 
To stop receiving notification emails like this one, please contact
['"commits@geode.apache.org" <commits@geode.apache.org>'].

Mime
View raw message