lucene-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sh...@apache.org
Subject svn commit: r1141060 [3/21] - in /lucene/dev/branches/branch_3x: dev-tools/eclipse/ dev-tools/maven/lucene/contrib/facet/ lucene/contrib/ lucene/contrib/facet/ lucene/contrib/facet/src/ lucene/contrib/facet/src/examples/ lucene/contrib/facet/src/exampl...
Date Wed, 29 Jun 2011 11:53:19 GMT
Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/AssociationsPayloadIterator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/AssociationsPayloadIterator.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/AssociationsPayloadIterator.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/AssociationsPayloadIterator.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,235 @@
+package org.apache.lucene.facet.enhancements.association;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+
+import org.apache.lucene.facet.index.params.CategoryListParams;
+import org.apache.lucene.facet.search.PayloadIntDecodingIterator;
+import org.apache.lucene.util.collections.IntIterator;
+import org.apache.lucene.util.collections.IntToIntMap;
+import org.apache.lucene.util.encoding.SimpleIntDecoder;
+
+/**
+ * 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.
+ */
+
+/**
+ * Allows easy iteration over the associations payload, decoding and breaking it
+ * to (ordinal, value) pairs, stored in a hash.
+ * 
+ * @lucene.experimental
+ */
+public class AssociationsPayloadIterator {
+
+  /**
+   * Default Term for associations
+   */
+  public static final Term ASSOCIATION_POSTING_TERM = new Term(
+      CategoryListParams.DEFAULT_TERM.field(),
+      AssociationEnhancement.CATEGORY_LIST_TERM_TEXT);
+
+  /**
+   * Hash mapping to ordinals to the associated int value
+   */
+  private IntToIntMap ordinalToAssociationMap;
+
+  /**
+   * An inner payload decoder which actually goes through the posting and
+   * decode the ints representing the ordinals and the values
+   */
+  private PayloadIntDecodingIterator associationPayloadIter;
+
+  /**
+   * Marking whether there are associations (at all) in the given index
+   */
+  private boolean hasAssociations = false;
+
+  /**
+   * The long-special-value returned for ordinals which have no associated int
+   * value. It is not in the int range of values making it a valid mark.
+   */
+  public final static long NO_ASSOCIATION = Integer.MAX_VALUE + 1;
+
+  /**
+   * Construct a new association-iterator, initializing the inner payload
+   * iterator, with the supplied term and checking whether there are any
+   * associations within the given index
+   * 
+   * @param reader
+   *            a reader containing the postings to be iterated
+   * @param field
+   *            the field containing the relevant associations list term
+   */
+  public AssociationsPayloadIterator(IndexReader reader, String field)
+      throws IOException {
+    // Initialize the payloadDecodingIterator
+    associationPayloadIter = new PayloadIntDecodingIterator(
+        reader,
+        // TODO (Facet): should consolidate with AssociationListTokenizer which
+        // uses AssociationEnhancement.getCatTermText()
+        new Term(field, AssociationEnhancement.CATEGORY_LIST_TERM_TEXT),
+        new SimpleIntDecoder());
+
+    // Check whether there are any associations
+    hasAssociations = associationPayloadIter.init();
+
+    ordinalToAssociationMap = new IntToIntMap();
+  }
+
+  /**
+   * Skipping to the next document, fetching its associations & populating the
+   * map.
+   * 
+   * @param docId
+   *            document id to be skipped to
+   * @return true if the document contains associations and they were fetched
+   *         correctly. false otherwise.
+   * @throws IOException
+   *             on error
+   */
+  public boolean setNextDoc(int docId) throws IOException {
+    ordinalToAssociationMap.clear();
+    boolean docContainsAssociations = false;
+    try {
+      docContainsAssociations = fetchAssociations(docId);
+    } catch (IOException e) {
+      IOException ioe = new IOException(
+          "An Error occured while reading a document's associations payload (docId="
+              + docId + ")");
+      ioe.initCause(e);
+      throw ioe;
+    }
+
+    return docContainsAssociations;
+  }
+
+  /**
+   * Get int association value for the given ordinal. <br>
+   * The return is either an int value casted as long if the ordinal has an
+   * associated value. Otherwise the returned value would be
+   * {@link #NO_ASSOCIATION} which is 'pure long' value (e.g not in the int
+   * range of values)
+   * 
+   * @param ordinal
+   *            for which the association value is requested
+   * @return the associated int value (encapsulated in a long) if the ordinal
+   *         had an associated value, or {@link #NO_ASSOCIATION} otherwise
+   */
+  public long getAssociation(int ordinal) {
+    if (ordinalToAssociationMap.containsKey(ordinal)) {
+      return ordinalToAssociationMap.get(ordinal);
+    }
+
+    return NO_ASSOCIATION;
+  }
+
+  /**
+   * Get an iterator over the ordinals which has an association for the
+   * document set by {@link #setNextDoc(int)}.
+   */
+  public IntIterator getAssociatedOrdinals() {
+    return ordinalToAssociationMap.keyIterator();
+  }
+
+  /**
+   * Skips to the given docId, getting the values in pairs of (ordinal, value)
+   * and populating the map
+   * 
+   * @param docId
+   *            document id owning the associations
+   * @return true if associations were fetched successfully, false otherwise
+   * @throws IOException
+   *             on error
+   */
+  private boolean fetchAssociations(int docId) throws IOException {
+    // No associations at all? don't bother trying to seek the docID in the
+    // posting
+    if (!hasAssociations) {
+      return false;
+    }
+
+    // No associations for this document? well, nothing to decode than,
+    // return false
+    if (!associationPayloadIter.skipTo(docId)) {
+      return false;
+    }
+
+    // loop over all the values decoded from the payload in pairs.
+    for (;;) {
+      // Get the ordinal
+      long ordinal = associationPayloadIter.nextCategory();
+
+      // if no ordinal - it's the end of data, break the loop
+      if (ordinal > Integer.MAX_VALUE) {
+        break;
+      }
+
+      // get the associated value
+      long association = associationPayloadIter.nextCategory();
+      // If we're at this step - it means we have an ordinal, do we have
+      // an association for it?
+      if (association > Integer.MAX_VALUE) {
+        // No association!!! A Broken Pair!! PANIC!
+        throw new IOException(
+            "ERROR! Associations should come in pairs of (ordinal, value), yet this payload has an odd number of values! (docId="
+                + docId + ")");
+      }
+      // Populate the map with the given ordinal and association pair
+      ordinalToAssociationMap.put((int) ordinal, (int) association);
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime
+        * result
+        + ((associationPayloadIter == null) ? 0
+            : associationPayloadIter.hashCode());
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    }
+    
+    if (obj == null) {
+      return false;
+    }
+    
+    if (getClass() != obj.getClass()) {
+      return false;
+    }
+    
+    AssociationsPayloadIterator other = (AssociationsPayloadIterator) obj;
+    if (associationPayloadIter == null) {
+      if (other.associationPayloadIter != null) {
+        return false;
+      }
+    } else if (!associationPayloadIter.equals(other.associationPayloadIter)) {
+      return false;
+    }
+    return true;
+  }
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/package.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/package.html?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/package.html (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/association/package.html Wed Jun 29 11:53:10 2011
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>Association category enhancements</title>
+</head>
+<body>
+<h1>Association category enhancements</h1>
+
+A {@link org.apache.lucene.facet.enhancements.CategoryEnhancement CategoryEnhancement} 
+for adding associations data to the index (categories with 
+{@link org.apache.lucene.facet.enhancements.association.AssociationProperty AssociationProperty}'s).
+ 
+</body>
+</html>
\ No newline at end of file

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/package.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/package.html?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/package.html (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/package.html Wed Jun 29 11:53:10 2011
@@ -0,0 +1,32 @@
+<html>
+<head>
+<title>Enhanced category features</title>
+</head>
+<body>
+<h1>Enhanced category features</h1>
+
+Mechanisms for addition of enhanced category features.
+<p>A {@link org.apache.lucene.facet.enhancements.CategoryEnhancement CategoryEnhancement}
+(which can correspond to a 
+{@link org.apache.lucene.facet.index.attributes.CategoryProperty CategoryProperty}) 
+can contribute to the index in two possible ways:
+<ol>
+	<li>To each category with data relevant to the enhancement, 
+	add	this data to the category's token payload, through 
+	{@link org.apache.lucene.facet.enhancements.CategoryEnhancement#getCategoryTokenBytes(CategoryAttribute) CategoryEnhancement.getCategoryTokenBytes()}.
+	This data will be read during search using 
+	{@link org.apache.lucene.facet.enhancements.CategoryEnhancement#extractCategoryTokenData(byte[],	int, int) CategoryEnhancement.extractCategoryTokenData()}.
+	</li>
+	<li>To each document which contains categories with data relevant	to the enhancement, add a 
+	{@link org.apache.lucene.facet.index.streaming.CategoryListTokenizer CategoryListTokenizer} through 
+	{@link org.apache.lucene.facet.enhancements.CategoryEnhancement#getCategoryListTokenizer CategoryEnhancement.getCategoryListTokenizer()} . 
+	The 
+	{@link org.apache.lucene.facet.index.streaming.CategoryListTokenizer CategoryListTokenizer} 
+	should add a single token which includes all the enhancement relevant data from the categories. 
+	The category list	token's text is defined by 
+	{@link org.apache.lucene.facet.enhancements.CategoryEnhancement#getCategoryListTermText() CategoryEnhancement.getCategoryListTermText()}.
+	</li>
+</ol>
+
+</body>
+</html>

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/DefaultEnhancementsIndexingParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/DefaultEnhancementsIndexingParams.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/DefaultEnhancementsIndexingParams.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/DefaultEnhancementsIndexingParams.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,98 @@
+package org.apache.lucene.facet.enhancements.params;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.lucene.facet.enhancements.CategoryEnhancement;
+import org.apache.lucene.facet.index.attributes.CategoryProperty;
+import org.apache.lucene.facet.index.params.CategoryListParams;
+import org.apache.lucene.facet.index.params.PerDimensionIndexingParams;
+
+/**
+ * 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.
+ */
+
+/**
+ * Default implementation of {@link EnhancementsIndexingParams} 
+ * 
+ * @lucene.experimental
+ */
+public class DefaultEnhancementsIndexingParams extends
+    PerDimensionIndexingParams implements EnhancementsIndexingParams {
+
+  private List<CategoryEnhancement> enhancedCategories;
+
+  /**
+   * Construct with a certain {@link CategoryEnhancement enhancement}
+   * @throws IllegalArgumentException if no enhancements are provided
+   */
+  public DefaultEnhancementsIndexingParams(CategoryEnhancement... enhancements) {
+    super();
+    validateparams(enhancements);
+    addCategoryEnhancements(enhancements);
+  }
+
+  private void validateparams(CategoryEnhancement... enhancements) {
+    if (enhancements==null || enhancements.length<1) {
+      throw new IllegalArgumentException("at least one enhancement is required");
+    }
+  }
+
+  /**
+   * Construct with certain {@link CategoryEnhancement enhancements}
+   * and {@link CategoryListParams}
+   * @throws IllegalArgumentException if no enhancements are provided
+   */
+  public DefaultEnhancementsIndexingParams(
+      CategoryListParams categoryListParams,
+      CategoryEnhancement... enhancements) {
+    super(categoryListParams);
+    validateparams(enhancements);
+    addCategoryEnhancements(enhancements);
+  }
+
+  public void addCategoryEnhancements(CategoryEnhancement... enhancements) {
+    if (enhancedCategories == null) {
+      enhancedCategories = new ArrayList<CategoryEnhancement>();
+    }
+    for (CategoryEnhancement categoryEnhancement : enhancements) {
+      enhancedCategories.add(categoryEnhancement);
+    }
+  }
+
+  public List<CategoryEnhancement> getCategoryEnhancements() {
+    if (enhancedCategories == null || enhancedCategories.isEmpty()) {
+      return null;
+    }
+    return enhancedCategories;
+  }
+
+  public List<Class<? extends CategoryProperty>> getRetainableProperties() {
+    if (enhancedCategories == null) {
+      return null;
+    }
+    List<Class<? extends CategoryProperty>> retainableProperties = new ArrayList<Class<? extends CategoryProperty>>();
+    for (CategoryEnhancement enhancement : enhancedCategories) {
+      if (enhancement.getRetainableProperty() != null) {
+        retainableProperties.add(enhancement.getRetainableProperty());
+      }
+    }
+    if (retainableProperties.isEmpty()) {
+      return null;
+    }
+    return retainableProperties;
+  }
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/EnhancementsIndexingParams.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/EnhancementsIndexingParams.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/EnhancementsIndexingParams.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/EnhancementsIndexingParams.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,66 @@
+package org.apache.lucene.facet.enhancements.params;
+
+import java.util.List;
+
+import org.apache.lucene.facet.enhancements.CategoryEnhancement;
+import org.apache.lucene.facet.enhancements.EnhancementsDocumentBuilder;
+import org.apache.lucene.facet.index.attributes.CategoryProperty;
+import org.apache.lucene.facet.index.params.FacetIndexingParams;
+import org.apache.lucene.facet.index.streaming.CategoryParentsStream;
+
+/**
+ * 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.
+ */
+
+/**
+ * {@link FacetIndexingParams Facet indexing parameters} for defining
+ * {@link CategoryEnhancement category enhancements}. It must contain at least
+ * one enhancement, otherwise nothing is "enhanced" about it. When there are
+ * more than one, the order matters - see {@link #getCategoryEnhancements()}.
+ * 
+ * @see EnhancementsDocumentBuilder
+ * @lucene.experimental
+ */
+public interface EnhancementsIndexingParams extends FacetIndexingParams {
+
+  /**
+   * Add {@link CategoryEnhancement}s to the indexing parameters
+   * @param enhancements enhancements to add
+   */
+  public void addCategoryEnhancements(CategoryEnhancement... enhancements);
+
+  /**
+   * Get a list of the active category enhancements. If no enhancements exist
+   * return {@code null}. The order of enhancements in the returned list
+   * dictates the order in which the enhancements data appear in the category
+   * tokens payload.
+   * 
+   * @return A list of the active category enhancements, or {@code null} if
+   *         there are no enhancements.
+   */
+  public List<CategoryEnhancement> getCategoryEnhancements();
+
+  /**
+   * Get a list of {@link CategoryProperty} classes to be retained when
+   * creating {@link CategoryParentsStream}.
+   * 
+   * @return the list of {@link CategoryProperty} classes to be retained when
+   *         creating {@link CategoryParentsStream}, or {@code null} if there
+   *         are no such properties.
+   */
+  public List<Class<? extends CategoryProperty>> getRetainableProperties();
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/package.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/package.html?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/package.html (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/enhancements/params/package.html Wed Jun 29 11:53:10 2011
@@ -0,0 +1,16 @@
+<html>
+<head>
+<title>Enhanced category features</title>
+</head>
+<body>
+<h1>Enhanced category features</h1>
+
+{@link org.apache.lucene.facet.index.params.FacetIndexingParams FacetIndexingParams} 
+used by 
+{@link org.apache.lucene.facet.enhancements.EnhancementsDocumentBuilder EnhancementsDocumentBuilder}
+for adding 
+{@link org.apache.lucene.facet.enhancements.CategoryEnhancement CategoryEnhancement}'s
+to the indexing parameters, and accessing them during indexing and search.
+
+</body>
+</html>
\ No newline at end of file

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryContainer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryContainer.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryContainer.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryContainer.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,282 @@
+package org.apache.lucene.facet.index;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.lucene.util.Attribute;
+
+import org.apache.lucene.facet.FacetException;
+import org.apache.lucene.facet.index.attributes.CategoryAttribute;
+import org.apache.lucene.facet.index.attributes.CategoryAttributeImpl;
+import org.apache.lucene.facet.index.attributes.CategoryProperty;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+
+/**
+ * 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.
+ */
+
+/**
+ * A container to add categories which are to be introduced to
+ * {@link CategoryDocumentBuilder#setCategories(Iterable)}. Categories can be
+ * added with Properties. 
+ * 
+ * @lucene.experimental
+ */
+public class CategoryContainer implements Iterable<CategoryAttribute>, Serializable {
+
+  protected transient Map<CategoryPath, CategoryAttribute> map;
+
+  /**
+   * Constructor.
+   */
+  public CategoryContainer() {
+    map = new HashMap<CategoryPath, CategoryAttribute>();
+  }
+
+  /**
+   * Add a category.
+   * 
+   * @param categoryPath
+   *            The path of the category.
+   * @return The {@link CategoryAttribute} of the category.
+   */
+  public CategoryAttribute addCategory(CategoryPath categoryPath) {
+    return mapCategoryAttribute(categoryPath);
+  }
+
+  /**
+   * Add a category with a property.
+   * 
+   * @param categoryPath
+   *            The path of the category.
+   * @param property
+   *            The property to associate to the category.
+   * @return The {@link CategoryAttribute} of the category.
+   */
+  public CategoryAttribute addCategory(CategoryPath categoryPath,
+      CategoryProperty property) {
+    /*
+     * This method is a special case of addCategory with multiple
+     * properties, but it is kept here for two reasons: 1) Using the array
+     * version has some performance cost, and 2) it is expected that most
+     * calls will be for this version (single property).
+     */
+    CategoryAttribute ca = mapCategoryAttribute(categoryPath);
+    ca.addProperty(property);
+    return ca;
+  }
+
+  /**
+   * Add a category with multiple properties.
+   * 
+   * @param categoryPath
+   *            The path of the category.
+   * @param properties
+   *            The properties to associate to the category.
+   * @return The {@link CategoryAttribute} of the category.
+   * @throws FacetException
+   *             When the category already has a property of the same type as
+   *             one of the new properties, and merging for this property type
+   *             is prohibited.
+   */
+  public CategoryAttribute addCategory(CategoryPath categoryPath,
+      CategoryProperty... properties) throws FacetException {
+    CategoryAttribute ca = mapCategoryAttribute(categoryPath);
+    for (CategoryProperty attribute : properties) {
+      ca.addProperty(attribute);
+    }
+    return ca;
+  }
+
+  /**
+   * Add an entire {@link CategoryAttribute}.
+   * 
+   * @param categoryAttribute
+   *            The {@link CategoryAttribute} to add.
+   * @return The {@link CategoryAttribute} of the category (could be different
+   *         from the one provided).
+   * @throws FacetException
+   */
+  public CategoryAttribute addCategory(CategoryAttribute categoryAttribute)
+  throws FacetException {
+    CategoryAttribute ca = mapCategoryAttribute(categoryAttribute
+        .getCategoryPath());
+    Set<Class<? extends CategoryProperty>> propertyClasses = categoryAttribute
+    .getPropertyClasses();
+    if (propertyClasses != null) {
+      for (Class<? extends CategoryProperty> propertyClass : propertyClasses) {
+        ca.addProperty(categoryAttribute.getProperty(propertyClass));
+      }
+    }
+    return ca;
+  }
+
+  /**
+   * Get the {@link CategoryAttribute} object for a specific
+   * {@link CategoryPath}, from the map.
+   */
+  private final CategoryAttribute mapCategoryAttribute(
+      CategoryPath categoryPath) {
+    CategoryAttribute ca = map.get(categoryPath);
+    if (ca == null) {
+      ca = new CategoryAttributeImpl(categoryPath);
+      map.put(categoryPath, ca);
+    }
+    return ca;
+  }
+
+  /**
+   * Get the {@link CategoryAttribute} this container has for a certain
+   * category, or {@code null} if the category is not in the container.
+   * 
+   * @param categoryPath
+   *            The category path of the requested category.
+   */
+  public CategoryAttribute getCategoryAttribute(CategoryPath categoryPath) {
+    return map.get(categoryPath);
+  }
+
+  public Iterator<CategoryAttribute> iterator() {
+    return map.values().iterator();
+  }
+
+  /**
+   * Remove all categories.
+   */
+  public void clear() {
+    map.clear();
+  }
+
+  /**
+   * Add the categories from another {@link CategoryContainer} to this one.
+   * 
+   * @param other
+   *            The {@link CategoryContainer} to take categories from.
+   * @throws FacetException
+   *             If any prohibited merge of category properties is attempted.
+   */
+  public void merge(CategoryContainer other) throws FacetException {
+    for (CategoryAttribute categoryAttribute : other.map.values()) {
+      addCategory(categoryAttribute);
+    }
+  }
+
+  /**
+   * Get the number of categories in the container.
+   * 
+   * @return The number of categories in the container.
+   */
+  public int size() {
+    return map.size();
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder builder = new StringBuilder("CategoryContainer");
+    for (CategoryAttribute ca : map.values()) {
+      builder.append('\n');
+      builder.append('\t');
+      builder.append(ca.toString());
+    }
+    return builder.toString();
+  }
+  
+  /**
+   * Serialize object content to given {@link ObjectOutputStream}
+   */
+  private void writeObject(ObjectOutputStream out) throws IOException {
+    out.defaultWriteObject();
+    // write the number of categories
+    out.writeInt(size());
+    // write the category attributes
+    for (CategoryAttribute ca : this) {
+      serializeCategoryAttribute(out, ca);
+    }
+  }
+
+  /**
+   * Serialize each of the {@link CategoryAttribute}s to the given
+   * {@link ObjectOutputStream}.<br>
+   * NOTE: {@link CategoryProperty}s are {@link Serializable}, but do not
+   * assume that Lucene's {@link Attribute}s are as well
+   * @throws IOException 
+   */
+  protected void serializeCategoryAttribute(ObjectOutputStream out,
+      CategoryAttribute ca) throws IOException {
+    out.writeObject(ca.getCategoryPath());
+    Set<Class<? extends CategoryProperty>> propertyClasses = ca.getPropertyClasses();
+    if (propertyClasses != null) {
+      out.writeInt(propertyClasses.size());
+      for (Class<? extends CategoryProperty> clazz : propertyClasses) {
+        out.writeObject(ca.getProperty(clazz));
+      }
+    } else {
+      out.writeInt(0);
+    }
+  }
+  
+  /**
+   * Deserialize object from given {@link ObjectInputStream}
+   */
+  private void readObject(ObjectInputStream in) throws IOException,
+      ClassNotFoundException {
+    in.defaultReadObject();
+    map = new HashMap<CategoryPath, CategoryAttribute>();
+    int size = in.readInt();
+    for (int i = 0; i < size; i++) {
+      deserializeCategoryAttribute(in);
+    }
+  }
+
+  /**
+   * De-Serialize each of the {@link CategoryAttribute}s from the given
+   * {@link ObjectInputStream}.
+   */
+  protected void deserializeCategoryAttribute(ObjectInputStream in)
+      throws IOException, ClassNotFoundException {
+    CategoryPath cp = (CategoryPath) in.readObject();
+    int nProperties = in.readInt();
+    if (nProperties == 0) {
+      addCategory(cp);
+    } else {
+      for (int j = 0; j < nProperties; j++) {
+        CategoryProperty property = (CategoryProperty) in.readObject();
+        addCategory(cp, property);
+      }
+    }
+  }
+  
+  @Override
+  public boolean equals(Object o) {
+    if (! (o instanceof CategoryContainer)) {
+      return false;
+    }
+    
+    CategoryContainer that = (CategoryContainer)o;
+    return this.map.equals(that.map);
+  }
+  
+  @Override
+  public int hashCode() {
+    return map.hashCode();
+  }
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryDocumentBuilder.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryDocumentBuilder.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryDocumentBuilder.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryDocumentBuilder.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,298 @@
+package org.apache.lucene.facet.index;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+import org.apache.lucene.DocumentBuilder;
+import org.apache.lucene.facet.index.attributes.CategoryAttribute;
+import org.apache.lucene.facet.index.attributes.CategoryAttributesIterable;
+import org.apache.lucene.facet.index.categorypolicy.OrdinalPolicy;
+import org.apache.lucene.facet.index.categorypolicy.PathPolicy;
+import org.apache.lucene.facet.index.params.DefaultFacetIndexingParams;
+import org.apache.lucene.facet.index.params.FacetIndexingParams;
+import org.apache.lucene.facet.index.streaming.CategoryAttributesStream;
+import org.apache.lucene.facet.index.streaming.CategoryListTokenizer;
+import org.apache.lucene.facet.index.streaming.CategoryParentsStream;
+import org.apache.lucene.facet.index.streaming.CategoryTokenizer;
+import org.apache.lucene.facet.index.streaming.CountingListTokenizer;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
+
+/**
+ * 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.
+ */
+
+/**
+ * A utility class which allows attachment of {@link CategoryPath}s or
+ * {@link CategoryAttribute}s to a given document using a taxonomy.<br>
+ * Construction could be done with either a given {@link FacetIndexingParams} or
+ * the default implementation {@link DefaultFacetIndexingParams}.<br>
+ * A CategoryDocumentBuilder can be reused by repeatedly setting the categories
+ * and building the document. Categories are provided either as
+ * {@link CategoryAttribute} elements through {@link #setCategories(Iterable)},
+ * or as {@link CategoryPath} elements through
+ * {@link #setCategoryPaths(Iterable)}.
+ * <p>
+ * Note that both {@link #setCategories(Iterable)} and
+ * {@link #setCategoryPaths(Iterable)} return this
+ * {@link CategoryDocumentBuilder}, allowing the following pattern: {@code new
+ * CategoryDocumentBuilder(taxonomy,
+ * params).setCategories(categories).build(doc)}.
+ * 
+ * @lucene.experimental
+ */
+public class CategoryDocumentBuilder implements DocumentBuilder {
+
+  /**
+   * A {@link TaxonomyWriter} for adding categories and retrieving their
+   * ordinals.
+   */
+  protected final TaxonomyWriter taxonomyWriter;
+
+  /**
+   * Parameters to be used when indexing categories.
+   */
+  protected final FacetIndexingParams indexingParams;
+
+  /**
+   * A list of fields which is filled at ancestors' construction and used
+   * during {@link CategoryDocumentBuilder#build(Document)}.
+   */
+  protected final ArrayList<Field> fieldList = new ArrayList<Field>();
+
+  protected Map<String, List<CategoryAttribute>> categoriesMap;
+
+  /**
+   * Creating a facets document builder with default facet indexing
+   * parameters.<br>
+   * See:
+   * {@link #CategoryDocumentBuilder(TaxonomyWriter, FacetIndexingParams)}
+   * 
+   * @param taxonomyWriter
+   *            to which new categories will be added, as well as translating
+   *            known categories to ordinals
+   * @throws IOException
+   * 
+   */
+  public CategoryDocumentBuilder(TaxonomyWriter taxonomyWriter)
+      throws IOException {
+    this(taxonomyWriter, new DefaultFacetIndexingParams());
+  }
+
+  /**
+   * Creating a facets document builder with a given facet indexing parameters
+   * object.<br>
+   * 
+   * @param taxonomyWriter
+   *            to which new categories will be added, as well as translating
+   *            known categories to ordinals
+   * @param params
+   *            holds all parameters the indexing process should use such as
+   *            category-list parameters
+   * @throws IOException
+   */
+  public CategoryDocumentBuilder(TaxonomyWriter taxonomyWriter,
+      FacetIndexingParams params) throws IOException {
+    this.taxonomyWriter = taxonomyWriter;
+    this.indexingParams = params;
+    this.categoriesMap = new HashMap<String, List<CategoryAttribute>>();
+  }
+
+  /**
+   * Set the categories of the document builder from an {@link Iterable} of
+   * {@link CategoryPath} objects.
+   * 
+   * @param categoryPaths
+   *            An iterable of CategoryPath objects which holds the categories
+   *            (facets) which will be added to the document at
+   *            {@link #build(Document)}
+   * @return This CategoryDocumentBuilder, to enable this one line call:
+   *         {@code new} {@link #CategoryDocumentBuilder(TaxonomyWriter)}.
+   *         {@link #setCategoryPaths(Iterable)}.{@link #build(Document)}.
+   * @throws IOException
+   */
+  public CategoryDocumentBuilder setCategoryPaths(
+      Iterable<CategoryPath> categoryPaths) throws IOException {
+    if (categoryPaths == null) {
+      fieldList.clear();
+      return this;
+    }
+    return setCategories(new CategoryAttributesIterable(categoryPaths));
+  }
+
+  /**
+   * Set the categories of the document builder from an {@link Iterable} of
+   * {@link CategoryAttribute} objects.
+   * 
+   * @param categories
+   *            An iterable of {@link CategoryAttribute} objects which holds
+   *            the categories (facets) which will be added to the document at
+   *            {@link #build(Document)}
+   * @return This CategoryDocumentBuilder, to enable this one line call:
+   *         {@code new} {@link #CategoryDocumentBuilder(TaxonomyWriter)}.
+   *         {@link #setCategories(Iterable)}.{@link #build(Document)}.
+   * @throws IOException
+   */
+  public CategoryDocumentBuilder setCategories(
+      Iterable<CategoryAttribute> categories) throws IOException {
+    fieldList.clear();
+    if (categories == null) {
+      return this;
+    }
+
+    // get field-name to a list of facets mapping as different facets could
+    // be added to different category-lists on different fields
+    fillCategoriesMap(categories);
+
+    // creates a different stream for each different field
+    for (Entry<String, List<CategoryAttribute>> e : categoriesMap
+        .entrySet()) {
+      // create a category attributes stream for the array of facets
+      CategoryAttributesStream categoryAttributesStream = new CategoryAttributesStream(
+          e.getValue());
+
+      // Set a suitable {@link TokenStream} using
+      // CategoryParentsStream, followed by CategoryListTokenizer and
+      // CategoryTokenizer composition (the ordering of the last two is
+      // not mandatory).
+      CategoryParentsStream parentsStream = (CategoryParentsStream) getParentsStream(categoryAttributesStream);
+      CategoryListTokenizer categoryListTokenizer = getCategoryListTokenizer(parentsStream);
+      CategoryTokenizer stream = getCategoryTokenizer(categoryListTokenizer);
+
+      // Finally creating a suitable field with stream and adding it to a
+      // master field-list, used during the build process (see
+      // super.build())
+      fieldList.add(new Field(e.getKey(), stream));
+    }
+
+    return this;
+  }
+
+  /**
+   * Get a stream of categories which includes the parents, according to
+   * policies defined in indexing parameters.
+   * 
+   * @param categoryAttributesStream
+   *            The input stream
+   * @return The parents stream.
+   * @see OrdinalPolicy OrdinalPolicy (for policy of adding category tokens for parents)
+   * @see PathPolicy PathPolicy (for policy of adding category <b>list</b> tokens for parents)
+   */
+  protected TokenStream getParentsStream(
+      CategoryAttributesStream categoryAttributesStream) {
+    return new CategoryParentsStream(categoryAttributesStream,
+        taxonomyWriter, indexingParams);
+  }
+
+  /**
+   * Fills the categories mapping between a field name and a list of
+   * categories that belongs to it according to this builder's
+   * {@link FacetIndexingParams} object
+   * 
+   * @param categories
+   *            Iterable over the category attributes
+   */
+  protected void fillCategoriesMap(Iterable<CategoryAttribute> categories)
+      throws IOException {
+    categoriesMap.clear();
+
+    // for-each category
+    for (CategoryAttribute category : categories) {
+      // extracting the field-name to which this category belongs
+      String fieldName = indexingParams.getCategoryListParams(
+          category.getCategoryPath()).getTerm().field();
+
+      // getting the list of categories which belongs to that field
+      List<CategoryAttribute> list = categoriesMap.get(fieldName);
+
+      // if no such list exists
+      if (list == null) {
+        // adding a new one to the map
+        list = new ArrayList<CategoryAttribute>();
+        categoriesMap.put(fieldName, list);
+      }
+
+      // adding the new category to the list
+      list.add(category.clone());
+    }
+  }
+
+  /**
+   * Get a category list tokenizer (or a series of such tokenizers) to create
+   * the <b>category list tokens</b>.
+   * 
+   * @param categoryStream
+   *            A stream containing {@link CategoryAttribute} with the
+   *            relevant data.
+   * @return The category list tokenizer (or series of tokenizers) to be used
+   *         in creating category list tokens.
+   */
+  protected CategoryListTokenizer getCategoryListTokenizer(
+      TokenStream categoryStream) {
+    return getCountingListTokenizer(categoryStream);
+  }
+
+  /**
+   * Get a {@link CountingListTokenizer} for creating counting list token.
+   * 
+   * @param categoryStream
+   *            A stream containing {@link CategoryAttribute}s with the
+   *            relevant data.
+   * @return A counting list tokenizer to be used in creating counting list
+   *         token.
+   */
+  protected CountingListTokenizer getCountingListTokenizer(
+      TokenStream categoryStream) {
+    return new CountingListTokenizer(categoryStream, indexingParams);
+  }
+
+  /**
+   * Get a {@link CategoryTokenizer} to create the <b>category tokens</b>.
+   * This method can be overridden for adding more attributes to the category
+   * tokens.
+   * 
+   * @param categoryStream
+   *            A stream containing {@link CategoryAttribute} with the
+   *            relevant data.
+   * @return The {@link CategoryTokenizer} to be used in creating category
+   *         tokens.
+   * @throws IOException
+   */
+  protected CategoryTokenizer getCategoryTokenizer(TokenStream categoryStream)
+      throws IOException {
+    return new CategoryTokenizer(categoryStream, indexingParams);
+  }
+
+  /**
+   * Adds the fields created in one of the "set" methods to the document
+   */
+  public Document build(Document doc) {
+    for (Field f : fieldList) {
+      f.setOmitNorms(true);
+      doc.add(f);
+    }
+    return doc;
+  }
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryListPayloadStream.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryListPayloadStream.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryListPayloadStream.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/CategoryListPayloadStream.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,65 @@
+package org.apache.lucene.facet.index;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.apache.lucene.util.encoding.IntEncoder;
+
+/**
+ * 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.
+ */
+
+/**
+ * Accumulates category IDs for a single document, for writing in byte array
+ * form, for example, to a Lucene Payload.
+ * 
+ * @lucene.experimental
+ */
+public class CategoryListPayloadStream {
+
+  private ByteArrayOutputStream baos = new ByteArrayOutputStream(50);
+  private IntEncoder encoder;
+
+  /** Creates a Payload stream using the specified encoder. */
+  public CategoryListPayloadStream(IntEncoder encoder) {
+    this.encoder = encoder;
+    this.encoder.reInit(baos);
+  }
+
+  /** Appends an integer to the stream. */
+  public void appendIntToStream(int intValue) throws IOException {
+    encoder.encode(intValue);
+  }
+
+  /** Returns the streamed bytes so far accumulated, as an array of bytes. */
+  public byte[] convertStreamToByteArray() {
+    try {
+      encoder.close();
+      return baos.toByteArray();
+    } catch (IOException e) {
+      // This cannot happen, because of BAOS (no I/O).
+      return new byte[0];
+    }
+  }
+
+  /** Resets this stream to begin building a new payload. */
+  public void reset() throws IOException {
+    encoder.close();
+    baos.reset();
+    encoder.reInit(baos);
+  }
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/FacetsPayloadProcessorProvider.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/FacetsPayloadProcessorProvider.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/FacetsPayloadProcessorProvider.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/FacetsPayloadProcessorProvider.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,187 @@
+package org.apache.lucene.facet.index;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.index.PayloadProcessorProvider;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.store.Directory;
+
+import org.apache.lucene.facet.index.params.CategoryListParams;
+import org.apache.lucene.facet.index.params.FacetIndexingParams;
+import org.apache.lucene.facet.taxonomy.lucene.LuceneTaxonomyWriter.OrdinalMap;
+import org.apache.lucene.util.encoding.IntDecoder;
+import org.apache.lucene.util.encoding.IntEncoder;
+
+/**
+ * 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.
+ */
+
+/**
+ * A {@link PayloadProcessorProvider} for updating facets ordinal references,
+ * based on an ordinal map. You should use this code in conjunction with merging
+ * taxonomies - after you merge taxonomies, you receive an {@link OrdinalMap}
+ * which maps the 'old' payloads to the 'new' ones. You can use that map to
+ * re-map the payloads which contain the facets information (ordinals) either
+ * before or while merging the indexes.
+ * <p>
+ * For re-mapping the ordinals before you merge the indexes, do the following:
+ * 
+ * <pre>
+ * // merge the old taxonomy with the new one.
+ * OrdinalMap map = LuceneTaxonomyWriter.addTaxonomies();
+ * int[] ordmap = map.getMap();
+ * 
+ * // re-map the ordinals on the old directory.
+ * Directory oldDir;
+ * FacetsPayloadProcessorProvider fppp = new FacetsPayloadProcessorProvider(
+ *     oldDir, ordmap);
+ * IndexWriterConfig conf = new IndexWriterConfig(VER, ANALYZER);
+ * conf.setMergePolicy(new ForceOptimizeMergePolicy());
+ * IndexWriter writer = new IndexWriter(oldDir, conf);
+ * writer.setPayloadProcessorProvider(fppp);
+ * writer.optimize();
+ * writer.close();
+ * 
+ * // merge that directory with the new index.
+ * IndexWriter newWriter; // opened on the 'new' Directory
+ * newWriter.addIndexes(oldDir);
+ * newWriter.commit();
+ * </pre>
+ * 
+ * For re-mapping the ordinals during index merge, do the following:
+ * 
+ * <pre>
+ * // merge the old taxonomy with the new one.
+ * OrdinalMap map = LuceneTaxonomyWriter.addTaxonomies();
+ * int[] ordmap = map.getMap();
+ * 
+ * // Add the index and re-map ordinals on the go
+ * IndexReader r = IndexReader.open(oldDir);
+ * IndexWriterConfig conf = new IndexWriterConfig(VER, ANALYZER);
+ * IndexWriter writer = new IndexWriter(newDir, conf);
+ * writer.setPayloadProcessorProvider(fppp);
+ * writer.addIndexes(r);
+ * writer.commit();
+ * </pre>
+ * <p>
+ * <b>NOTE:</b> while the second example looks simpler, IndexWriter may trigger
+ * a long merge due to addIndexes. The first example avoids this perhaps
+ * unneeded merge, as well as can be done separately (e.g. on another node)
+ * before the index is merged.
+ * 
+ * @lucene.experimental
+ */
+public class FacetsPayloadProcessorProvider extends PayloadProcessorProvider {
+  
+  private final Directory workDir;
+  
+  private final DirPayloadProcessor dirProcessor;
+
+  /**
+   * Construct FacetsPayloadProcessorProvider with FacetIndexingParams
+   * 
+   * @param dir the {@link Directory} containing the segments to update
+   * @param ordinalMap an array mapping previous facets ordinals to new ones
+   * @param indexingParams the facets indexing parameters
+   */
+  public FacetsPayloadProcessorProvider(Directory dir, int[] ordinalMap,
+                                        FacetIndexingParams indexingParams) {
+    workDir = dir;
+    dirProcessor = new FacetsDirPayloadProcessor(indexingParams, ordinalMap);
+  }
+  
+  @Override
+  public DirPayloadProcessor getDirProcessor(Directory dir) throws IOException {
+    if (workDir != dir) {
+      return null;
+    }
+    return dirProcessor;
+  }
+  
+  public static class FacetsDirPayloadProcessor extends DirPayloadProcessor {
+    
+    private final Map<Term, CategoryListParams> termMap = new HashMap<Term, CategoryListParams>(1);
+    
+    private final int[] ordinalMap;
+    
+    /**
+     * Construct FacetsDirPayloadProcessor with custom FacetIndexingParams
+     * @param ordinalMap an array mapping previous facets ordinals to new ones
+     * @param indexingParams the facets indexing parameters
+     */
+    protected FacetsDirPayloadProcessor(FacetIndexingParams indexingParams, int[] ordinalMap) {
+      this.ordinalMap = ordinalMap;
+      for (CategoryListParams params: indexingParams.getAllCategoryListParams()) {
+        termMap.put(params.getTerm(), params);
+      }
+    }
+    
+    @Override
+    public PayloadProcessor getProcessor(Term term) throws IOException {
+      CategoryListParams params = termMap.get(term);
+      if (params == null) {
+        return null;
+      }
+      return new FacetsPayloadProcessor(params, ordinalMap);
+    }
+
+  }
+  
+  /** A PayloadProcessor for updating facets ordinal references, based on an ordinal map */
+  public static class FacetsPayloadProcessor extends PayloadProcessor {
+    
+    private final IntEncoder encoder;
+    private final IntDecoder decoder;
+    private final int[] ordinalMap;
+    private final ByteArrayOutputStream os = new ByteArrayOutputStream();
+    
+    /**
+     * @param params defines the encoding of facet ordinals as payload
+     * @param ordinalMap an array mapping previous facets ordinals to new ones
+     */
+    protected FacetsPayloadProcessor(CategoryListParams params, int[] ordinalMap) {
+      encoder = params.createEncoder();
+      decoder = encoder.createMatchingDecoder();
+      this.ordinalMap = ordinalMap;
+    }
+    
+    @Override
+    public int payloadLength() throws IOException {
+      return os.size();
+    }
+
+    @Override
+    public byte[] processPayload(byte[] payload, int start, int length) throws IOException {
+      InputStream is = new ByteArrayInputStream(payload, start, length);
+      decoder.reInit(is);
+      os.reset();
+      encoder.reInit(os);
+      long ordinal;
+      while ((ordinal = decoder.decode()) != IntDecoder.EOS) {
+        int newOrdinal = ordinalMap[(int)ordinal];
+        encoder.encode(newOrdinal);      
+      }
+      encoder.close();
+      return os.toByteArray();
+    }
+  }
+  
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttribute.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttribute.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttribute.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttribute.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,129 @@
+package org.apache.lucene.facet.index.attributes;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.apache.lucene.util.Attribute;
+
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+
+/**
+ * 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.
+ */
+
+/**
+ * An attribute which contains for a certain category the {@link CategoryPath}
+ * and additional properties.
+ * 
+ * @lucene.experimental
+ */
+public interface CategoryAttribute extends Attribute {
+
+  /**
+   * Set the content of this {@link CategoryAttribute} from another
+   * {@link CategoryAttribute} object.
+   * 
+   * @param other
+   *            The {@link CategoryAttribute} to take the content from.
+   */
+  public void set(CategoryAttribute other);
+
+  /**
+   * Sets the category path value of this attribute.
+   * 
+   * @param cp
+   *            A category path. May not be null.
+   */
+  public void setCategoryPath(CategoryPath cp);
+
+  /**
+   * Returns the value of this attribute: a category path.
+   * 
+   * @return The category path last assigned to this attribute, or null if
+   *         none has been assigned.
+   */
+  public CategoryPath getCategoryPath();
+
+  /**
+   * Add a property. The property can be later retrieved using
+   * {@link #getProperty(Class)} with this property class .<br>
+   * Adding multiple properties of the same class is forbidden.
+   * 
+   * @param property
+   *            The property to add.
+   * @throws UnsupportedOperationException
+   *             When attempting to add a property of a class that was added
+   *             before and merge is prohibited.
+   */
+  public void addProperty(CategoryProperty property)
+      throws UnsupportedOperationException;
+
+  /**
+   * Get a property of a certain property class.
+   * 
+   * @param propertyClass
+   *            The required property class.
+   * @return The property of the given class, or null if no such property
+   *         exists.
+   */
+  public CategoryProperty getProperty(
+      Class<? extends CategoryProperty> propertyClass);
+
+  /**
+   * Get a property of one of given property classes.
+   * 
+   * @param propertyClasses
+   *            The property classes.
+   * @return A property matching one of the given classes, or null if no such
+   *         property exists.
+   */
+  public CategoryProperty getProperty(
+      Collection<Class<? extends CategoryProperty>> propertyClasses);
+
+  /**
+   * Get all the active property classes.
+   * 
+   * @return A set containing the active property classes, or {@code null} if
+   *         there are no properties.
+   */
+  public Set<Class<? extends CategoryProperty>> getPropertyClasses();
+
+  /**
+   * Clone this {@link CategoryAttribute}.
+   * 
+   * @return A clone of this {@link CategoryAttribute}.
+   */
+  public CategoryAttribute clone();
+
+  /**
+   * Resets this attribute to its initial value: a null category path and no
+   * properties.
+   */
+  public void clear();
+
+  /**
+   * Clear all properties.
+   */
+  public void clearProperties();
+
+  /**
+   * Remove an property of a certain property class.
+   * 
+   * @param propertyClass
+   *            The required property class.
+   */
+  public void remove(Class<? extends CategoryProperty> propertyClass);
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributeImpl.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributeImpl.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributeImpl.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributeImpl.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,192 @@
+package org.apache.lucene.facet.index.attributes;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Set;
+
+import org.apache.lucene.util.AttributeImpl;
+
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+
+/**
+ * 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.
+ */
+
+/**
+ * An implementation of {@link CategoryAttribute}.
+ * 
+ * @lucene.experimental
+ */
+public final class CategoryAttributeImpl extends AttributeImpl implements
+    CategoryAttribute {
+
+  /**
+   * The category path instance.
+   */
+  protected CategoryPath categoryPath;
+
+  /**
+   * A map of properties associated to the current category path.
+   */
+  protected HashMap<Class<? extends CategoryProperty>, CategoryProperty> properties;
+
+  /**
+   * Construct an empty CategoryAttributeImpl.
+   */
+  public CategoryAttributeImpl() {
+    // do nothing
+  }
+
+  /**
+   * Construct a CategoryAttributeImpl with the given CategoryPath.
+   * 
+   * @param categoryPath
+   *            The category path to use.
+   */
+  public CategoryAttributeImpl(CategoryPath categoryPath) {
+    setCategoryPath(categoryPath);
+  }
+
+  public void set(CategoryAttribute other) {
+    ((CategoryAttributeImpl) other).copyTo(this);
+  }
+
+  /**
+   * Returns the category path value.
+   * 
+   * @return The category path last assigned to this attribute, or null if
+   *         none has been assigned.
+   */
+  public CategoryPath getCategoryPath() {
+    return categoryPath;
+  }
+
+  public void setCategoryPath(CategoryPath cp) {
+    categoryPath = cp;
+  }
+
+  public void addProperty(CategoryProperty property)
+      throws UnsupportedOperationException {
+    if (properties == null) {
+      properties = new HashMap<Class<? extends CategoryProperty>, CategoryProperty>();
+    }
+    CategoryProperty existing = properties.get(property.getClass());
+    if (existing == null) {
+      properties.put(property.getClass(), property);
+    } else {
+      existing.merge(property);
+    }
+  }
+
+  public CategoryProperty getProperty(
+      Class<? extends CategoryProperty> propertyClass) {
+    if (properties == null) {
+      return null;
+    }
+    return properties.get(propertyClass);
+  }
+
+  public CategoryProperty getProperty(
+      Collection<Class<? extends CategoryProperty>> propertyClasses) {
+    if (properties == null) {
+      return null;
+    }
+    for (Class<? extends CategoryProperty> propertyClass : propertyClasses) {
+      CategoryProperty categoryProperty = properties.get(propertyClass);
+      if (categoryProperty != null) {
+        return categoryProperty;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public void copyTo(AttributeImpl target) {
+    ((CategoryAttributeImpl) target).categoryPath = this.categoryPath;
+    ((CategoryAttributeImpl) target).properties = this.properties;
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public CategoryAttribute clone() {
+    CategoryAttributeImpl ca = (CategoryAttributeImpl) super.clone();
+    if (categoryPath != null) {
+      ca.categoryPath = (CategoryPath) categoryPath.clone();
+    }
+    if (properties != null && !properties.isEmpty()) {
+      ca.properties = (HashMap<Class<? extends CategoryProperty>, CategoryProperty>) properties
+          .clone();
+    }
+    return ca;
+  }
+
+  @Override
+  public void clear() {
+    categoryPath = null;
+    clearProperties();
+  }
+
+  public void clearProperties() {
+    if (properties != null) {
+      properties.clear();
+    }
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (!(o instanceof CategoryAttributeImpl)) {
+      return false;
+    }
+    CategoryAttributeImpl other = (CategoryAttributeImpl) o;
+    if (categoryPath == null) {
+      return (other.categoryPath == null);
+    }
+    if (!categoryPath.equals(other.categoryPath)) {
+      return false;
+    }
+    if (properties == null || properties.isEmpty()) {
+      return (other.properties == null || other.properties.isEmpty());
+    }
+    return properties.equals(other.properties);
+  }
+
+  @Override
+  public int hashCode() {
+    if (categoryPath == null) {
+      return 0;
+    }
+    int hashCode = categoryPath.hashCode();
+    if (properties != null && !properties.isEmpty()) {
+      hashCode ^= properties.hashCode();
+    }
+    return hashCode;
+  }
+
+  public Set<Class<? extends CategoryProperty>> getPropertyClasses() {
+    if (properties == null || properties.isEmpty()) {
+      return null;
+    }
+    return properties.keySet();
+  }
+
+  public void remove(Class<? extends CategoryProperty> propertyClass) {
+    properties.remove(propertyClass);
+  }
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributesIterable.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributesIterable.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributesIterable.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryAttributesIterable.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,69 @@
+package org.apache.lucene.facet.index.attributes;
+
+import java.util.Iterator;
+
+import org.apache.lucene.facet.index.streaming.CategoryAttributesStream;
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+
+/**
+ * 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.
+ */
+
+/**
+ * This class transforms an {@link Iterable} of {@link CategoryPath} objects
+ * into an {@link Iterable} of {@link CategoryAttribute} objects, which can be
+ * used to construct a {@link CategoryAttributesStream}.
+ * 
+ * @lucene.experimental
+ */
+public class CategoryAttributesIterable implements Iterable<CategoryAttribute> {
+
+  private Iterable<CategoryPath> inputIterable;
+
+  public CategoryAttributesIterable(Iterable<CategoryPath> inputIterable) {
+    this.inputIterable = inputIterable;
+  }
+
+  public Iterator<CategoryAttribute> iterator() {
+    return new CategoryAttributesIterator(this.inputIterable);
+  }
+
+  private static class CategoryAttributesIterator implements Iterator<CategoryAttribute> {
+
+    private Iterator<CategoryPath> internalIterator;
+    private CategoryAttributeImpl categoryAttributeImpl;
+
+    public CategoryAttributesIterator(Iterable<CategoryPath> inputIterable) {
+      this.internalIterator = inputIterable.iterator();
+      this.categoryAttributeImpl = new CategoryAttributeImpl();
+    }
+
+    public boolean hasNext() {
+      return this.internalIterator.hasNext();
+    }
+
+    public CategoryAttribute next() {
+      this.categoryAttributeImpl.setCategoryPath(this.internalIterator
+          .next());
+      return this.categoryAttributeImpl;
+    }
+
+    public void remove() {
+      this.internalIterator.remove();
+    }
+
+  }
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryProperty.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryProperty.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryProperty.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/CategoryProperty.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,51 @@
+package org.apache.lucene.facet.index.attributes;
+
+import java.io.Serializable;
+
+import org.apache.lucene.facet.index.CategoryContainer;
+
+/**
+ * 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.
+ */
+
+/**
+ * Property that can be added to {@link CategoryAttribute}s during indexing.
+ * Note that properties are put in a map and could be shallow copied during
+ * {@link CategoryAttributeImpl#clone()}, therefore reuse of
+ * {@link CategoryProperty} objects is not recommended. Also extends
+ * {@link Serializable}, making the {@link CategoryContainer} serialization more
+ * elegant.
+ * 
+ * @lucene.experimental
+ */
+public interface CategoryProperty extends Serializable {
+
+  /**
+   * When adding categories with properties to a certain document, it is
+   * possible that the same category will be added more than once with
+   * different instances of the same property. This method defined how to
+   * treat such cases, by merging the newly added property into the one
+   * previously added. Implementing classes can assume that this method will
+   * be called only with a property of the same class.
+   * 
+   * @param other
+   *            The category property to merge.
+   * @throws UnsupportedOperationException
+   *             If merging is prohibited for this property.
+   */
+  public void merge(CategoryProperty other)
+      throws UnsupportedOperationException;
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/OrdinalProperty.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/OrdinalProperty.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/OrdinalProperty.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/OrdinalProperty.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,71 @@
+package org.apache.lucene.facet.index.attributes;
+
+/**
+ * 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.
+ */
+
+/**
+ * A {@link CategoryProperty} holding the ordinal from the taxonomy of the
+ * current category in {@link CategoryAttribute}.
+ * <p>
+ * Ordinal properties are added internally during processing of category
+ * streams, and it is recommended not to use it externally.
+ * 
+ * @lucene.experimental
+ */
+public class OrdinalProperty implements CategoryProperty {
+
+  protected int ordinal = -1;
+
+  public int getOrdinal() {
+    return ordinal;
+  }
+
+  public boolean hasBeenSet() {
+    return this.ordinal >= 0;
+  }
+
+  public void setOrdinal(int value) {
+    this.ordinal = value;
+  }
+
+  public void clear() {
+    this.ordinal = -1;
+  }
+
+  @Override
+  public boolean equals(Object other) {
+    if (other == this) {
+      return true;
+    }
+    if (!(other instanceof OrdinalProperty)) {
+      return false;
+    }
+    OrdinalProperty o = (OrdinalProperty) other;
+    return o.ordinal == this.ordinal;
+  }
+
+  @Override
+  public int hashCode() {
+    return this.ordinal;
+  }
+
+  public void merge(CategoryProperty other) {
+    throw new UnsupportedOperationException(
+    "Merging ordinal attributes is prohibited");
+  }
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/package.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/package.html?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/package.html (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/attributes/package.html Wed Jun 29 11:53:10 2011
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>Category attributes and their properties for indexing</title>
+</head>
+<body>
+<h1>Category attributes and their properties for indexing</h1>
+
+Attributes for a {@link org.apache.lucene.facet.taxonomy.CategoryPath category}, 
+possibly containing 
+{@link org.apache.lucene.facet.index.attributes.CategoryProperty category property}'s.
+
+</body>
+</html>
\ No newline at end of file

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultOrdinalPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultOrdinalPolicy.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultOrdinalPolicy.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultOrdinalPolicy.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,43 @@
+package org.apache.lucene.facet.index.categorypolicy;
+
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
+
+/**
+ * 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.
+ */
+
+/**
+ * This class filters our the ROOT category ID. For more information see
+ * {@link OrdinalPolicy}.
+ * 
+ * @lucene.experimental
+ */
+public class DefaultOrdinalPolicy implements OrdinalPolicy {
+
+  /**
+   * Filters out (returns false) ordinals equal or less than
+   * {@link TaxonomyReader#ROOT_ORDINAL}. true otherwise.
+   */
+  public boolean shouldAdd(int ordinal) {
+    return ordinal > TaxonomyReader.ROOT_ORDINAL;
+  }
+
+  /**
+   * Implemented as NO-OP as the default is not taxonomy dependent
+   */
+  public void init(TaxonomyWriter taxonomyWriter) { }
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultPathPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultPathPolicy.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultPathPolicy.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/DefaultPathPolicy.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,38 @@
+package org.apache.lucene.facet.index.categorypolicy;
+
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+
+/**
+ * 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.
+ */
+
+/**
+ * This class filters our the ROOT category path. For more information see
+ * {@link PathPolicy}.
+ * 
+ * @lucene.experimental
+ */
+public class DefaultPathPolicy implements PathPolicy {
+
+  /**
+   * Filters out (returns false) CategoryPaths equal or less than
+   * {@link TaxonomyReader#ROOT_ORDINAL}. true otherwise.
+   */
+  public boolean shouldAdd(CategoryPath categoryPath) {
+    return categoryPath.length() > 0;
+  }
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelOrdinalPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelOrdinalPolicy.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelOrdinalPolicy.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelOrdinalPolicy.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,71 @@
+package org.apache.lucene.facet.index.categorypolicy;
+
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
+
+/**
+ * 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.
+ */
+
+/**
+ * Filter out any "top level" category ordinals. <br> {@link #shouldAdd(int)}.
+ * 
+ * @lucene.experimental
+ */
+public class NonTopLevelOrdinalPolicy implements OrdinalPolicy {
+
+  /**
+   * The taxonomyWriter with which the given ordinals' parent is determined.
+   */
+  private TaxonomyWriter taxonomyWriter;
+
+  /**
+   * Constructs a new non-top-level-ordinal-filter. With a given
+   * taxonomyWriter.
+   * 
+   */
+  public NonTopLevelOrdinalPolicy() {
+    this.taxonomyWriter = null;
+  }
+
+  /** 
+   * @param taxonomyWriter
+   *            A relevant taxonomyWriter object, with which ordinals sent to
+   *            {@link #shouldAdd(int)} are examined.
+   */
+  public void init(TaxonomyWriter taxonomyWriter) {
+    this.taxonomyWriter = taxonomyWriter;
+  }
+  
+  /**
+   * Filters out ordinal which are ROOT or who's parent is ROOT. In order to
+   * determine if a parent is root, there's a need for
+   * {@link TaxonomyWriter#getParent(int)}.
+   */
+  public boolean shouldAdd(int ordinal) {
+    if (ordinal > TaxonomyReader.ROOT_ORDINAL) {
+      try {
+        if (this.taxonomyWriter.getParent(ordinal) > TaxonomyReader.ROOT_ORDINAL) {
+          return true;
+        }
+      } catch (Exception e) {
+        return false;
+      }
+    }
+    return false;
+  }
+
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelPathPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelPathPolicy.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelPathPolicy.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/NonTopLevelPathPolicy.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,43 @@
+package org.apache.lucene.facet.index.categorypolicy;
+
+import org.apache.lucene.facet.taxonomy.CategoryPath;
+import org.apache.lucene.facet.taxonomy.TaxonomyReader;
+
+/**
+ * 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.
+ */
+
+/**
+ * This class filters our the ROOT category, and it's direct descendants. For
+ * more information see {@link PathPolicy}.
+ * 
+ * @lucene.experimental
+ */
+public class NonTopLevelPathPolicy implements PathPolicy {
+
+  /**
+   * The shortest path length delivered is two components (root + one child).
+   */
+  public final int DEFAULT_MINIMAL_SUBPATH_LENGTH = 2;
+
+  /**
+   * Filters out (returns false) CategoryPaths equal or less than
+   * {@link TaxonomyReader#ROOT_ORDINAL}. true otherwise.
+   */
+  public boolean shouldAdd(CategoryPath categoryPath) {
+    return categoryPath.length() >= DEFAULT_MINIMAL_SUBPATH_LENGTH;
+  }
+}

Added: lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/OrdinalPolicy.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/OrdinalPolicy.java?rev=1141060&view=auto
==============================================================================
--- lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/OrdinalPolicy.java (added)
+++ lucene/dev/branches/branch_3x/lucene/contrib/facet/src/java/org/apache/lucene/facet/index/categorypolicy/OrdinalPolicy.java Wed Jun 29 11:53:10 2011
@@ -0,0 +1,56 @@
+package org.apache.lucene.facet.index.categorypolicy;
+
+import java.io.Serializable;
+
+import org.apache.lucene.facet.index.streaming.CategoryParentsStream;
+import org.apache.lucene.facet.taxonomy.TaxonomyWriter;
+
+/**
+ * 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.
+ */
+
+/**
+ * Filtering category ordinals in {@link CategoryParentsStream}, where a given
+ * category ordinal is added to the stream, and than its parents are being added
+ * one after the other using {@link TaxonomyWriter#getParent(int)}. <br>
+ * That loop should have a stop point - the default approach (excluding the
+ * ROOT) is implemented in {@link DefaultOrdinalPolicy}.
+ * 
+ * @lucene.experimental
+ */
+public interface OrdinalPolicy extends Serializable {
+
+  /**
+   * Check whether a given category ordinal should be added to the stream.
+   * 
+   * @param ordinal
+   *            A given category ordinal which is to be tested for stream
+   *            addition.
+   * @return <code>true</code> if the category should be added.
+   *         <code>false</code> otherwise.
+   */
+  public abstract boolean shouldAdd(int ordinal);
+
+  /**
+   * Initialize the policy with a TaxonomyWriter. This method can be
+   * implemented as noop if the ordinal policy is not taxonomy dependent
+   * 
+   * @param taxonomyWriter
+   *            A relevant taxonomyWriter object, with which ordinals sent to
+   *            {@link #shouldAdd(int)} are examined.
+   */
+  public abstract void init(TaxonomyWriter taxonomyWriter);
+}
\ No newline at end of file



Mime
View raw message