All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.browseengine.bobo.facets.impl.CombinedFloatFacetIterator Maven / Gradle / Ivy

There is a newer version: 3.1.2
Show newest version
/**
 * This software is licensed to you under the Apache License, Version 2.0 (the
 * "Apache License").
 *
 * LinkedIn's contributions are made under the Apache License. If you contribute
 * to the Software, the contributions will be deemed to have been made under the
 * Apache License, unless you expressly indicate otherwise. Please do not make any
 * contributions that would be inconsistent with the Apache License.
 *
 * You may obtain a copy of the Apache License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, this software
 * distributed under the Apache License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Apache
 * License for the specific language governing permissions and limitations for the
 * software governed under the Apache License.
 *
 * © 2012 LinkedIn Corp. All Rights Reserved.  
 */

package com.browseengine.bobo.facets.impl;

import java.util.List;
import java.util.NoSuchElementException;

import com.browseengine.bobo.api.FloatFacetIterator;
import com.browseengine.bobo.facets.data.TermFloatList;

/**
 * @author "Xiaoyang Gu"
 * 
 */
public class CombinedFloatFacetIterator extends FloatFacetIterator
{

  public float facet;

  private static class FloatIteratorNode
  {
    public FloatFacetIterator _iterator;
    public float _curFacet;
    public int _curFacetCount;

    public FloatIteratorNode(FloatFacetIterator iterator)
    {
      _iterator = iterator;
      _curFacet = TermFloatList.VALUE_MISSING;
      _curFacetCount = 0;
    }

    public boolean fetch(int minHits)
    {
      if (minHits > 0)
        minHits = 1;
      if ((_curFacet = _iterator.nextFloat(minHits)) != TermFloatList.VALUE_MISSING)
      {
        _curFacetCount = _iterator.count;
        return true;
      }
      _curFacet = TermFloatList.VALUE_MISSING;
      _curFacetCount = 0;
      return false;
    }

    public String peek()// bad
    {
      throw new UnsupportedOperationException();
      // if(_iterator.hasNext())
      // {
      // return _iterator.getFacet();
      // }
      // return null;
    }
  }

  private final FloatFacetPriorityQueue _queue;

  private List _iterators;

  private CombinedFloatFacetIterator(final int length)
  {
    _queue = new FloatFacetPriorityQueue();
    _queue.initialize(length);
  }

  public CombinedFloatFacetIterator(final List iterators)
  {
    this(iterators.size());
    _iterators = iterators;
    for (FloatFacetIterator iterator : iterators)
    {
      FloatIteratorNode node = new FloatIteratorNode(iterator);
      if (node.fetch(1))
        _queue.add(node);
    }
    facet = TermFloatList.VALUE_MISSING;
    count = 0;
  }

  public CombinedFloatFacetIterator(final List iterators,
      int minHits)
  {
    this(iterators.size());
    _iterators = iterators;
    for (FloatFacetIterator iterator : iterators)
    {
      FloatIteratorNode node = new FloatIteratorNode(iterator);
      if (node.fetch(minHits))
        _queue.add(node);
    }
    facet = TermFloatList.VALUE_MISSING;
    count = 0;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.browseengine.bobo.api.FacetIterator#getFacet()
   */
  public String getFacet()
  {
    if (facet == TermFloatList.VALUE_MISSING) return null;
    return format(facet);
  }

  public String format(float val)
  {
    return _iterators.get(0).format(val);
  }

  public String format(Object val)
  {
    return _iterators.get(0).format(val);
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.browseengine.bobo.api.FacetIterator#getFacetCount()
   */
  public int getFacetCount()
  {
    return count;
  }

  /*
   * (non-Javadoc)
   * 
   * @see com.browseengine.bobo.api.FacetIterator#next()
   */
  public String next()
  {
    if (!hasNext())
      throw new NoSuchElementException("No more facets in this iteration");

    FloatIteratorNode node = _queue.top();

    facet = node._curFacet;
    float next = TermFloatList.VALUE_MISSING;
    count = 0;
    while (hasNext())
    {
      node = _queue.top();
      next = node._curFacet;
      if ((next != TermFloatList.VALUE_MISSING) && (next != facet))
      {
        return format(facet);
      }
      count += node._curFacetCount;
      if (node.fetch(1))
        _queue.updateTop();
      else
        _queue.pop();
    }
    return null;
  }

  /**
   * This version of the next() method applies the minHits from the facet spec
   * before returning the facet and its hitcount
   * 
   * @param minHits
   *          the minHits from the facet spec for CombinedFacetAccessible
   * @return The next facet that obeys the minHits
   */
  public String next(int minHits)
  {
    int qsize = _queue.size();
    if (qsize == 0)
    {
      facet = TermFloatList.VALUE_MISSING;
      count = 0;
      return null;
    }

    FloatIteratorNode node = _queue.top();
    facet = node._curFacet;
    count = node._curFacetCount;
    while (true)
    {
      if (node.fetch(minHits))
      {
        node = _queue.updateTop();
      } else
      {
        _queue.pop();
        if (--qsize > 0)
        {
          node = _queue.top();
        } else
        {
          // we reached the end. check if this facet obeys the minHits
          if (count < minHits)
          {
            facet = TermFloatList.VALUE_MISSING;
            count = 0;
            return null;
          }
          break;
        }
      }
      float next = node._curFacet;
      if (next != facet)
      {
        // check if this facet obeys the minHits
        if (count >= minHits)
          break;
        // else, continue iterating to the next facet
        facet = next;
        count = node._curFacetCount;
      } else
      {
        count += node._curFacetCount;
      }
    }
    return format(facet);
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.util.Iterator#hasNext()
   */
  public boolean hasNext()
  {
    return (_queue.size() > 0);
  }

  /*
   * (non-Javadoc)
   * 
   * @see java.util.Iterator#remove()
   */
  public void remove()
  {
    throw new UnsupportedOperationException(
        "remove() method not supported for Facet Iterators");
  }

  /**
   * Lucene PriorityQueue
   * 
   */
  public static class FloatFacetPriorityQueue
  {
    private int size;
    private int maxSize;
    protected FloatIteratorNode[] heap;

    /** Subclass constructors must call this. */
    protected final void initialize(int maxSize)
    {
      size = 0;
      int heapSize;
      if (0 == maxSize)
        // We allocate 1 extra to avoid if statement in top()
        heapSize = 2;
      else
        heapSize = maxSize + 1;
      heap = new FloatIteratorNode[heapSize];
      this.maxSize = maxSize;
    }

    public final void put(FloatIteratorNode element)
    {
      size++;
      heap[size] = element;
      upHeap();
    }

    public final FloatIteratorNode add(FloatIteratorNode element)
    {
      size++;
      heap[size] = element;
      upHeap();
      return heap[1];
    }

    public boolean insert(FloatIteratorNode element)
    {
      return insertWithOverflow(element) != element;
    }

    public FloatIteratorNode insertWithOverflow(FloatIteratorNode element)
    {
      if (size < maxSize)
      {
        put(element);
        return null;
      } else if (size > 0 && !(element._curFacet < heap[1]._curFacet))
      {
        FloatIteratorNode ret = heap[1];
        heap[1] = element;
        adjustTop();
        return ret;
      } else
      {
        return element;
      }
    }

    /** Returns the least element of the PriorityQueue in constant time. */
    public final FloatIteratorNode top()
    {
      // We don't need to check size here: if maxSize is 0,
      // then heap is length 2 array with both entries null.
      // If size is 0 then heap[1] is already null.
      return heap[1];
    }

    /**
     * Removes and returns the least element of the PriorityQueue in log(size)
     * time.
     */
    public final FloatIteratorNode pop()
    {
      if (size > 0)
      {
        FloatIteratorNode result = heap[1]; // save first value
        heap[1] = heap[size]; // move last to first
        heap[size] = null; // permit GC of objects
        size--;
        downHeap(); // adjust heap
        return result;
      } else
        return null;
    }

    public final void adjustTop()
    {
      downHeap();
    }

    public final FloatIteratorNode updateTop()
    {
      downHeap();
      return heap[1];
    }

    /** Returns the number of elements currently stored in the PriorityQueue. */
    public final int size()
    {
      return size;
    }

    /** Removes all entries from the PriorityQueue. */
    public final void clear()
    {
      for (int i = 0; i <= size; i++)
      {
        heap[i] = null;
      }
      size = 0;
    }

    private final void upHeap()
    {
      int i = size;
      FloatIteratorNode node = heap[i]; // save bottom node
      int j = i >>> 1;
      while (j > 0 && (node._curFacet < heap[j]._curFacet))
      {
        heap[i] = heap[j]; // shift parents down
        i = j;
        j = j >>> 1;
      }
      heap[i] = node; // install saved node
    }

    private final void downHeap()
    {
      int i = 1;
      FloatIteratorNode node = heap[i]; // save top node
      int j = i << 1; // find smaller child
      int k = j + 1;
      if (k <= size && (heap[k]._curFacet < heap[j]._curFacet))
      {
        j = k;
      }
      while (j <= size && (heap[j]._curFacet < node._curFacet))
      {
        heap[i] = heap[j]; // shift up child
        i = j;
        j = i << 1;
        k = j + 1;
        if (k <= size && (heap[k]._curFacet < heap[j]._curFacet))
        {
          j = k;
        }
      }
      heap[i] = node; // install saved node
    }
  }

  @Override
  public float nextFloat()
  {
    if (!hasNext())
      throw new NoSuchElementException("No more facets in this iteration");

    FloatIteratorNode node = _queue.top();

    facet = node._curFacet;
    float next = TermFloatList.VALUE_MISSING;
    count = 0;
    while (hasNext())
    {
      node = _queue.top();
      next = node._curFacet;
      if ((next != TermFloatList.VALUE_MISSING) && (next != facet))
      {
        return facet;
      }
      count += node._curFacetCount;
      if (node.fetch(1))
        _queue.updateTop();
      else
        _queue.pop();
    }
    return TermFloatList.VALUE_MISSING;
  }

  @Override
  public float nextFloat(int minHits)
  {
    int qsize = _queue.size();
    if (qsize == 0)
    {
      facet = TermFloatList.VALUE_MISSING;
      count = 0;
      return TermFloatList.VALUE_MISSING;
    }

    FloatIteratorNode node = _queue.top();
    facet = node._curFacet;
    count = node._curFacetCount;
    while (true)
    {
      if (node.fetch(minHits))
      {
        node = _queue.updateTop();
      } else
      {
        _queue.pop();
        if (--qsize > 0)
        {
          node = _queue.top();
        } else
        {
          // we reached the end. check if this facet obeys the minHits
          if (count < minHits)
          {
            facet = TermFloatList.VALUE_MISSING;
            count = 0;
          }
          break;
        }
      }
      float next = node._curFacet;
      if (next != facet)
      {
        // check if this facet obeys the minHits
        if (count >= minHits)
          break;
        // else, continue iterating to the next facet
        facet = next;
        count = node._curFacetCount;
      } else
      {
        count += node._curFacetCount;
      }
    }
    return facet;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy