Package com.browseengine.bobo.facets.impl

Source Code of com.browseengine.bobo.facets.impl.GeoFacetCountCollector$GeoRange

/**
*
*/
package com.browseengine.bobo.facets.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.browseengine.bobo.api.BrowseFacet;
import com.browseengine.bobo.api.FacetIterator;
import com.browseengine.bobo.api.FacetSpec;
import com.browseengine.bobo.facets.FacetCountCollector;
import com.browseengine.bobo.facets.data.TermStringList;
import com.browseengine.bobo.facets.filter.GeoFacetFilter;
import com.browseengine.bobo.facets.impl.GeoFacetHandler.GeoFacetData;
import com.browseengine.bobo.util.BigFloatArray;
import com.browseengine.bobo.util.BigSegmentedArray;
import com.browseengine.bobo.util.GeoMatchUtil;
import com.browseengine.bobo.util.LazyBigIntArray;

/**
* @author nnarkhed
*
*/
public class GeoFacetCountCollector implements FacetCountCollector {

  private final String _name;
  private final FacetSpec _spec;
  private BigSegmentedArray _count;
  private int _countlength;
  private GeoFacetData _dataCache;
  private final TermStringList _predefinedRanges;
  private int _docBase;
  private GeoRange[] _ranges;
  private BigFloatArray _xvals;
  private BigFloatArray _yvals;
  private BigFloatArray _zvals;
    // variable to specify if the geo distance calculations are in miles. Default is miles
    private boolean _miles;
 
  public static class GeoRange {
    private final float _lat;
    private final float _lon;
    private final float _rad;
   
    public GeoRange(float lat, float lon, float radius) {
      _lat = lat;
      _lon = lon;
      _rad = radius;
    }

    /**
     * @return the latitude value
     */
    public float getLat() {
      return _lat;
    }

    /**
     * @return the longitude value
     */
    public float getLon() {
      return _lon;
    }

    /**
     * @return the radius
     */
    public float getRad() {
      return _rad;
    }
  }
 
  /**
   *
   * @param name         name of the Geo Facet
   * @param dataCache      The data cache for the Geo Facet
   * @param docBase      the base doc id
   * @param spec        the facet spec for this facet
   * @param predefinedRanges  List of ranges, where each range looks like <lat, lon: rad>
   * @param miles        variable to specify if the geo distance calculations are in miles. False indicates distance calculation is in kilometers
   */
  protected GeoFacetCountCollector(String name, GeoFacetData dataCache,
      int docBase, FacetSpec fspec, List<String> predefinedRanges, boolean miles) {
    _name = name;
    _dataCache = dataCache;
    _xvals = dataCache.get_xValArray();
    _yvals = dataCache.get_yValArray();
    _zvals = dataCache.get_zValArray();
    _spec = fspec;
    _predefinedRanges = new TermStringList();
    Collections.sort(predefinedRanges);
    _predefinedRanges.addAll(predefinedRanges);
    _docBase = docBase;
    _countlength = predefinedRanges.size();
    _count = new LazyBigIntArray(_countlength);
    _ranges = new GeoRange[predefinedRanges.size()];
    int index = 0;
    for(String range: predefinedRanges) {
      _ranges[index++] = parse(range);
    }
    _miles = miles;
  }

  /**
   * @param docid The docid for which the facet counts are to be calculated
   */
  public void collect(int docid) {
    float docX = _xvals.get(docid);
    float docY = _yvals.get(docid);
    float docZ = _zvals.get(docid);

    float radius, targetX, targetY, targetZ, delta;
    float xu, xl, yu, yl, zu, zl;
    int countIndex = -1;
    for(GeoRange range: _ranges) {
      // the countIndex for the count array should increment with the range index of the _ranges array
      countIndex++;
      if(_miles)
        radius = GeoMatchUtil.getMilesRadiusCosine(range.getRad());
      else
        radius = GeoMatchUtil.getKMRadiusCosine(range.getRad());
     
      float[] coords = GeoMatchUtil.geoMatchCoordsFromDegrees(range.getLat(), range.getLon());
      targetX = coords[0];
      targetY = coords[1];
      targetZ = coords[2];
     
      if(_miles)
        delta = (float)(range.getRad()/GeoMatchUtil.EARTH_RADIUS_MILES);
      else
        delta = (float)(range.getRad()/GeoMatchUtil.EARTH_RADIUS_KM);
     
      xu = targetX + delta;
      xl = targetX - delta;

      // try to see if the range checks can short circuit the actual inCircle check
      if(docX > xu || docX < xl) continue;

      yu = targetY + delta;
      yl = targetY - delta;

      if(docY > yu || docY < yl) continue;

      zu = targetZ + delta;
      zl = targetZ - delta;

      if(docZ > zu || docZ < zl) continue;

      if(GeoFacetFilter.inCircle(docX, docY, docZ, targetX, targetY, targetZ, radius)) {
        // if the lat, lon values of this docid match the current user-specified range, then increment the
        // appropriate count[] value
        _count.add(countIndex, _count.get(countIndex) + 1);
        // do not break here, since one document could lie in multiple user-specified ranges
      }       
    }
  }

  public void collectAll() {
    throw new UnsupportedOperationException("collectAll is not supported for Geo Facets yet");
  }

  /**
   * @return Count distribution for all the user specified range values
   */
  public BigSegmentedArray getCountDistribution() {
    BigSegmentedArray dist = null;
    if(_predefinedRanges != null) {
      dist = new LazyBigIntArray(_predefinedRanges.size());
      int distIdx = 0;
      for (int i = 0; i < _count.size(); i++) {
        int count = _count.get(i);
        dist.add(distIdx++, count);
      }
    }
    return dist;
  }

  public String getName() {
    return _name;
  }

  /**
   * @param value This value should be one of the user-specified ranges for this Facet Count Collector. Else an
   *              IllegalArgumentException will be raised
   * @return The BrowseFacet corresponding to the range value            
   */
  public BrowseFacet getFacet(String value) {
    if(_predefinedRanges != null) {
      int index = 0;
      if((index = _predefinedRanges.indexOf(value)) != -1) {
        BrowseFacet choice = new BrowseFacet();
        choice.setHitCount(_count.get(index));
        choice.setValue(value);
        return choice;
      }
      else {
        // user specified an unknown range value. the overhead to calculate the count for an unknown range value is high,
        // in the sense it requires to go through each docid in the index. Till we get a better solution, this operation is
        // unsupported
        throw new IllegalArgumentException("The value argument is not one of the user-specified ranges");       
      }
    }
    else {
      throw new IllegalArgumentException("There are no user-specified ranges for this Facet Count Collector object");
    }
  }

  public int getFacetHitsCount(Object value)
  {
    if(_predefinedRanges != null)
    {
      int index = 0;
      if((index = _predefinedRanges.indexOf(value)) != -1)
      {
        return _count.get(index);
      }
      else
      {
        throw new IllegalArgumentException("The value argument is not one of the user-specified ranges");       
      }
    }
    else
    {
      throw new IllegalArgumentException("There are no user-specified ranges for this Facet Count Collector object");
    }
  }

  /**
   * @return A list containing BrowseFacet objects for each of the user-specified ranges
   */
  public List<BrowseFacet> getFacets() {
    if(_spec != null) {
      int minHitCount = _spec.getMinHitCount();
      if(_ranges != null) {
        List<BrowseFacet> facets = new ArrayList<BrowseFacet>();
        int countIndex = -1;
        for(String value : _predefinedRanges) {
          countIndex++;
          if(_count.get(countIndex) >= minHitCount) {
            BrowseFacet choice = new BrowseFacet();
            choice.setHitCount(_count.get(countIndex));
            choice.setValue(value);
            facets.add(choice);
          }
        }
        return facets;
      }
      else {
        return FacetCountCollector.EMPTY_FACET_LIST;
      }
    }
    else {
      return FacetCountCollector.EMPTY_FACET_LIST;
    }
  }

  /**
   *
   * @param range Value should be of the format - lat , lon : radius
   * @return GeoRange object containing the lat, lon and radius value
   */
  public static GeoRange parse(String range) {
    String[] parts = range.split(":");
    if((parts == null) || (parts.length != 2))
      throw new IllegalArgumentException("Range value not in the expected format(lat, lon : radius)");
    String coord_part = parts[0];
    float rad = Float.parseFloat(parts[1].trim());
   
    String[] coords = coord_part.split(",");
    if((coords == null) || (coords.length != 2))
      throw new IllegalArgumentException("Range value not in the expected format(lat, lon : radius)");
    float lat = Float.parseFloat(coords[0].trim());
    float lon = Float.parseFloat(coords[1].trim());

    return new GeoRange(lat, lon, rad);
  }

  /* (non-Javadoc)
   * @see com.browseengine.bobo.api.FacetAccessible#close()
   */
  public void close()
  {   
  }
 
  public FacetIterator iterator() {
    return new DefaultFacetIterator(_predefinedRanges, _count, _countlength, true);
  }
}
TOP

Related Classes of com.browseengine.bobo.facets.impl.GeoFacetCountCollector$GeoRange

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.