/** * */ package com.browseengine.bobo.facets.impl; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Properties; import org.apache.lucene.index.AtomicReader; import org.apache.lucene.search.ScoreDoc; import com.browseengine.bobo.api.BoboSegmentReader; import com.browseengine.bobo.api.BrowseSelection; import com.browseengine.bobo.api.FacetSpec; import com.browseengine.bobo.facets.FacetCountCollector; import com.browseengine.bobo.facets.FacetCountCollectorSource; import com.browseengine.bobo.facets.FacetHandler.FacetDataNone; import com.browseengine.bobo.facets.RuntimeFacetHandler; import com.browseengine.bobo.facets.data.FacetDataCache; import com.browseengine.bobo.facets.filter.RandomAccessAndFilter; import com.browseengine.bobo.facets.filter.RandomAccessFilter; import com.browseengine.bobo.facets.impl.GeoFacetCountCollector.GeoRange; import com.browseengine.bobo.sort.DocComparator; import com.browseengine.bobo.sort.DocComparatorSource; public class GeoSimpleFacetHandler extends RuntimeFacetHandler<FacetDataNone> { protected final String _latFacetName; protected final String _longFacetName; protected RangeFacetHandler _latFacetHandler; protected RangeFacetHandler _longFacetHandler; public static class GeoLatLonRange { public final String latRange; public final String lonRange; public final float latStart; public final float latEnd; public final float lonStart; public final float lonEnd; public final float radius; private GeoLatLonRange(String latRange, String lonRange, float latStart, float latEnd, float lonStart, float lonEnd, float radius) { this.latRange = latRange; this.lonRange = lonRange; this.latStart = latStart; this.latEnd = latEnd; this.lonStart = lonStart; this.lonEnd = lonEnd; this.radius = radius; } public static GeoLatLonRange parse(String val) { GeoRange range = GeoFacetCountCollector.parse(val); float latStart = range.getLat() - range.getRad(); float latEnd = range.getLat() + range.getRad(); float lonStart = range.getLon() - range.getRad(); float lonEnd = range.getLon() + range.getRad(); StringBuilder buf = new StringBuilder(); buf.append("[").append(String.valueOf(latStart)).append(" TO ") .append(String.valueOf(latEnd)).append("]"); String latRange = buf.toString(); buf = new StringBuilder(); buf.append("[").append(String.valueOf(lonStart)).append(" TO ") .append(String.valueOf(lonEnd)).append("]"); String lonRange = buf.toString(); return new GeoLatLonRange(latRange, lonRange, latStart, latEnd, lonStart, lonEnd, range.getRad()); } } public GeoSimpleFacetHandler(String name, String latFacetName, String longFacetName) { super(name, new HashSet<String>(Arrays.asList(new String[] { latFacetName, longFacetName }))); _latFacetName = latFacetName; _longFacetName = longFacetName; } @Override public RandomAccessFilter buildRandomAccessFilter(String val, Properties props) throws IOException { GeoLatLonRange range = GeoLatLonRange.parse(val); RandomAccessFilter latFilter = _latFacetHandler.buildRandomAccessFilter(range.latRange, props); RandomAccessFilter longFilter = _longFacetHandler .buildRandomAccessFilter(range.lonRange, props); return new RandomAccessAndFilter( Arrays.asList(new RandomAccessFilter[] { latFilter, longFilter })); } @Override public RandomAccessFilter buildRandomAccessAndFilter(String[] vals, Properties props) throws IOException { List<String> latValList = new ArrayList<String>(vals.length); List<String> longValList = new ArrayList<String>(vals.length); for (String val : vals) { GeoLatLonRange range = GeoLatLonRange.parse(val); latValList.add(range.latRange); longValList.add(range.lonRange); } RandomAccessFilter latFilter = _latFacetHandler.buildRandomAccessAndFilter( latValList.toArray(new String[latValList.size()]), props); RandomAccessFilter longFilter = _longFacetHandler.buildRandomAccessAndFilter( longValList.toArray(new String[longValList.size()]), props); return new RandomAccessAndFilter( Arrays.asList(new RandomAccessFilter[] { latFilter, longFilter })); } @Override public RandomAccessFilter buildRandomAccessOrFilter(String[] vals, Properties props, boolean isNot) throws IOException { List<String> latValList = new ArrayList<String>(vals.length); List<String> longValList = new ArrayList<String>(vals.length); for (String val : vals) { GeoLatLonRange range = GeoLatLonRange.parse(val); latValList.add(range.latRange); longValList.add(range.lonRange); } RandomAccessFilter latFilter = _latFacetHandler.buildRandomAccessOrFilter( latValList.toArray(new String[latValList.size()]), props, isNot); RandomAccessFilter longFilter = _longFacetHandler.buildRandomAccessOrFilter( longValList.toArray(new String[longValList.size()]), props, isNot); return new RandomAccessAndFilter( Arrays.asList(new RandomAccessFilter[] { latFilter, longFilter })); } private static List<String> buildAllRangeStrings(String[] values) { if (values == null) return Collections.emptyList(); List<String> ranges = new ArrayList<String>(values.length); for (String value : values) { ranges.add(value); } return ranges; } @Override public FacetCountCollectorSource getFacetCountCollectorSource(final BrowseSelection sel, final FacetSpec fspec) { final List<String> list = buildAllRangeStrings(sel.getValues()); return new FacetCountCollectorSource() { // every string in the above list is of the form <latitude, longitude, radius>, which can be // interpreted by GeoSimpleFacetCountCollector @Override public FacetCountCollector getFacetCountCollector(BoboSegmentReader reader, int docBase) { FacetDataCache<?> latDataCache = _latFacetHandler.getFacetData(reader); FacetDataCache<?> longDataCache = _longFacetHandler.getFacetData(reader); return new GeoSimpleFacetCountCollector(_name, latDataCache, longDataCache, docBase, fspec, list); } }; } @Override public String[] getFieldValues(BoboSegmentReader reader, int docid) { String[] latValues = _latFacetHandler.getFieldValues(reader, docid); String[] longValues = _longFacetHandler.getFieldValues(reader, docid); String[] allValues = new String[latValues.length + longValues.length]; int index = 0; for (String value : latValues) { allValues[index++] = value; } for (String value : longValues) { allValues[index++] = value; } return allValues; } @Override public Object[] getRawFieldValues(BoboSegmentReader reader, int docid) { Object[] latValues = _latFacetHandler.getRawFieldValues(reader, docid); Object[] longValues = _longFacetHandler.getRawFieldValues(reader, docid); Object[] allValues = new Object[latValues.length + longValues.length]; int index = 0; for (Object value : latValues) { allValues[index++] = value; } for (Object value : longValues) { allValues[index++] = value; } return allValues; } @Override public FacetDataNone load(BoboSegmentReader reader) throws IOException { _latFacetHandler = (RangeFacetHandler) getDependedFacetHandler(_latFacetName); _longFacetHandler = (RangeFacetHandler) getDependedFacetHandler(_longFacetName); return FacetDataNone.instance; } @Override public DocComparatorSource getDocComparatorSource() { return new GeoFacetDocComparatorSource(this); } public static class GeoFacetDocComparatorSource extends DocComparatorSource { public GeoFacetDocComparatorSource(GeoSimpleFacetHandler geoSimpleFacetHandler) { } @Override public DocComparator getComparator(AtomicReader reader, int docbase) throws IOException { if (!(reader instanceof BoboSegmentReader)) throw new IllegalStateException( "reader not instance of " + BoboSegmentReader.class); return new DocComparator() { @Override public Comparable<?> value(ScoreDoc doc) { return 1; } @Override public int compare(ScoreDoc doc1, ScoreDoc doc2) { return 0; } }; } } }