Search in sources :

Example 1 with DistanceUnits

use of org.apache.solr.util.DistanceUnits in project lucene-solr by apache.

the class GeoDistValueSourceParser method parse.

@Override
public ValueSource parse(FunctionQParser fp) throws SyntaxError {
    // TODO: dispatch through SpatialQueryable in the future?
    //note: parseValueSourceList can't handle a field reference to an AbstractSpatialFieldType,
    // so those fields are expressly handled via sfield=
    List<ValueSource> sources = fp.parseValueSourceList();
    // "m" is a multi-value source, "x" is a single-value source
    // allow (m,m) (m,x,x) (x,x,m) (x,x,x,x)
    // if not enough points are present, "pt" will be checked first, followed by "sfield".
    MultiValueSource mv1 = null;
    MultiValueSource mv2 = null;
    if (sources.size() == 0) {
    // nothing to do now
    } else if (sources.size() == 1) {
        ValueSource vs = sources.get(0);
        if (!(vs instanceof MultiValueSource)) {
            throw new SyntaxError("geodist - invalid parameters:" + sources);
        }
        mv1 = (MultiValueSource) vs;
    } else if (sources.size() == 2) {
        ValueSource vs1 = sources.get(0);
        ValueSource vs2 = sources.get(1);
        if (vs1 instanceof MultiValueSource && vs2 instanceof MultiValueSource) {
            mv1 = (MultiValueSource) vs1;
            mv2 = (MultiValueSource) vs2;
        } else {
            mv1 = makeMV(sources, sources);
        }
    } else if (sources.size() == 3) {
        ValueSource vs1 = sources.get(0);
        ValueSource vs2 = sources.get(1);
        if (vs1 instanceof MultiValueSource) {
            // (m,x,x)
            mv1 = (MultiValueSource) vs1;
            mv2 = makeMV(sources.subList(1, 3), sources);
        } else {
            // (x,x,m)
            mv1 = makeMV(sources.subList(0, 2), sources);
            vs1 = sources.get(2);
            if (!(vs1 instanceof MultiValueSource)) {
                throw new SyntaxError("geodist - invalid parameters:" + sources);
            }
            mv2 = (MultiValueSource) vs1;
        }
    } else if (sources.size() == 4) {
        mv1 = makeMV(sources.subList(0, 2), sources);
        mv2 = makeMV(sources.subList(2, 4), sources);
    } else if (sources.size() > 4) {
        throw new SyntaxError("geodist - invalid parameters:" + sources);
    }
    if (mv1 == null) {
        mv1 = parsePoint(fp);
        mv2 = parseSfield(fp);
    } else if (mv2 == null) {
        mv2 = parsePoint(fp);
        if (mv2 == null)
            mv2 = parseSfield(fp);
    }
    if (mv1 == null || mv2 == null) {
        throw new SyntaxError("geodist - not enough parameters:" + sources);
    }
    // We have all the parameters at this point, now check if one of the points is constant
    //latLon
    double[] constants;
    constants = getConstants(mv1);
    MultiValueSource other = mv2;
    if (constants == null) {
        constants = getConstants(mv2);
        other = mv1;
    }
    // sfield can only be in mv2, according to the logic above
    if (mv2 instanceof SpatialStrategyMultiValueSource) {
        if (constants == null)
            throw new SyntaxError("When using AbstractSpatialFieldType (e.g. RPT not LatLonType)," + " the point must be supplied as constants");
        // note: uses Haversine by default but can be changed via distCalc=...
        SpatialStrategy strategy = ((SpatialStrategyMultiValueSource) mv2).strategy;
        DistanceUnits distanceUnits = ((SpatialStrategyMultiValueSource) mv2).distanceUnits;
        Point queryPoint = strategy.getSpatialContext().makePoint(constants[1], constants[0]);
        return strategy.makeDistanceValueSource(queryPoint, distanceUnits.multiplierFromDegreesToThisUnit());
    }
    if (constants != null && other instanceof VectorValueSource) {
        return new HaversineConstFunction(constants[0], constants[1], (VectorValueSource) other);
    }
    return new HaversineFunction(mv1, mv2, DistanceUtils.EARTH_MEAN_RADIUS_KM, true);
}
Also used : SyntaxError(org.apache.solr.search.SyntaxError) VectorValueSource(org.apache.lucene.queries.function.valuesource.VectorValueSource) ValueSource(org.apache.lucene.queries.function.ValueSource) DoubleConstValueSource(org.apache.lucene.queries.function.valuesource.DoubleConstValueSource) MultiValueSource(org.apache.lucene.queries.function.valuesource.MultiValueSource) VectorValueSource(org.apache.lucene.queries.function.valuesource.VectorValueSource) DistanceUnits(org.apache.solr.util.DistanceUnits) Point(org.locationtech.spatial4j.shape.Point) MultiValueSource(org.apache.lucene.queries.function.valuesource.MultiValueSource) SpatialStrategy(org.apache.lucene.spatial.SpatialStrategy)

Example 2 with DistanceUnits

use of org.apache.solr.util.DistanceUnits in project lucene-solr by apache.

the class SpatialHeatmapFacets method getHeatmapForField.

/** Called by {@link org.apache.solr.request.SimpleFacets} to compute heatmap facets. */
public static NamedList<Object> getHeatmapForField(String fieldKey, String fieldName, ResponseBuilder rb, SolrParams params, DocSet docSet) throws IOException {
    //get the strategy from the field type
    final SchemaField schemaField = rb.req.getSchema().getField(fieldName);
    final FieldType type = schemaField.getType();
    final PrefixTreeStrategy strategy;
    final DistanceUnits distanceUnits;
    // note: the two instanceof conditions is not ideal, versus one. If we start needing to add more then refactor.
    if ((type instanceof AbstractSpatialPrefixTreeFieldType)) {
        AbstractSpatialPrefixTreeFieldType rptType = (AbstractSpatialPrefixTreeFieldType) type;
        strategy = (PrefixTreeStrategy) rptType.getStrategy(fieldName);
        distanceUnits = rptType.getDistanceUnits();
    } else if (type instanceof RptWithGeometrySpatialField) {
        RptWithGeometrySpatialField rptSdvType = (RptWithGeometrySpatialField) type;
        strategy = rptSdvType.getStrategy(fieldName).getIndexStrategy();
        distanceUnits = rptSdvType.getDistanceUnits();
    } else {
        //FYI we support the term query one too but few people use that one
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "heatmap field needs to be of type " + SpatialRecursivePrefixTreeFieldType.class + " or " + RptWithGeometrySpatialField.class);
    }
    final SpatialContext ctx = strategy.getSpatialContext();
    //get the bbox (query Rectangle)
    String geomStr = params.getFieldParam(fieldKey, FacetParams.FACET_HEATMAP_GEOM);
    final Shape boundsShape = geomStr == null ? ctx.getWorldBounds() : SpatialUtils.parseGeomSolrException(geomStr, ctx);
    //get the grid level (possibly indirectly via distErr or distErrPct)
    final int gridLevel;
    Integer gridLevelObj = params.getFieldInt(fieldKey, FacetParams.FACET_HEATMAP_LEVEL);
    final int maxGridLevel = strategy.getGrid().getMaxLevels();
    if (gridLevelObj != null) {
        gridLevel = gridLevelObj;
        if (gridLevel <= 0 || gridLevel > maxGridLevel) {
            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, FacetParams.FACET_HEATMAP_LEVEL + " should be > 0 and <= " + maxGridLevel);
        }
    } else {
        //SpatialArgs has utility methods to resolve a 'distErr' from optionally set distErr & distErrPct. Arguably that
        // should be refactored to feel less weird than using it like this.
        SpatialArgs spatialArgs = new SpatialArgs(SpatialOperation.Intersects, /*ignored*/
        boundsShape == null ? ctx.getWorldBounds() : boundsShape);
        final Double distErrObj = params.getFieldDouble(fieldKey, FacetParams.FACET_HEATMAP_DIST_ERR);
        if (distErrObj != null) {
            // convert distErr units based on configured units
            spatialArgs.setDistErr(distErrObj * distanceUnits.multiplierFromThisUnitToDegrees());
        }
        spatialArgs.setDistErrPct(params.getFieldDouble(fieldKey, FacetParams.FACET_HEATMAP_DIST_ERR_PCT));
        double distErr = spatialArgs.resolveDistErr(ctx, DEFAULT_DIST_ERR_PCT);
        if (distErr <= 0) {
            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, FacetParams.FACET_HEATMAP_DIST_ERR_PCT + " or " + FacetParams.FACET_HEATMAP_DIST_ERR + " should be > 0 or instead provide " + FacetParams.FACET_HEATMAP_LEVEL + "=" + maxGridLevel + " if you insist on maximum detail");
        }
        //The SPT (grid) can lookup a grid level satisfying an error distance constraint
        gridLevel = strategy.getGrid().getLevelForDistance(distErr);
    }
    //Compute!
    final HeatmapFacetCounter.Heatmap heatmap;
    try {
        heatmap = HeatmapFacetCounter.calcFacets(strategy, rb.req.getSearcher().getTopReaderContext(), // turn DocSet into Bits
        getTopAcceptDocs(docSet, rb.req.getSearcher()), boundsShape, gridLevel, // will throw if exceeded
        params.getFieldInt(fieldKey, FacetParams.FACET_HEATMAP_MAX_CELLS, 100_000));
    } catch (IllegalArgumentException e) {
        //e.g. too many cells
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, e.toString(), e);
    }
    //Populate response
    NamedList<Object> result = new NamedList<>();
    result.add("gridLevel", gridLevel);
    result.add("columns", heatmap.columns);
    result.add("rows", heatmap.rows);
    result.add("minX", heatmap.region.getMinX());
    result.add("maxX", heatmap.region.getMaxX());
    result.add("minY", heatmap.region.getMinY());
    result.add("maxY", heatmap.region.getMaxY());
    boolean hasNonZero = false;
    for (int count : heatmap.counts) {
        if (count > 0) {
            hasNonZero = true;
            break;
        }
    }
    formatCountsAndAddToNL(fieldKey, rb, params, heatmap.columns, heatmap.rows, hasNonZero ? heatmap.counts : null, result);
    return result;
}
Also used : HeatmapFacetCounter(org.apache.lucene.spatial.prefix.HeatmapFacetCounter) SpatialArgs(org.apache.lucene.spatial.query.SpatialArgs) SpatialContext(org.locationtech.spatial4j.context.SpatialContext) Shape(org.locationtech.spatial4j.shape.Shape) NamedList(org.apache.solr.common.util.NamedList) FieldType(org.apache.solr.schema.FieldType) AbstractSpatialPrefixTreeFieldType(org.apache.solr.schema.AbstractSpatialPrefixTreeFieldType) SpatialRecursivePrefixTreeFieldType(org.apache.solr.schema.SpatialRecursivePrefixTreeFieldType) SchemaField(org.apache.solr.schema.SchemaField) RptWithGeometrySpatialField(org.apache.solr.schema.RptWithGeometrySpatialField) DistanceUnits(org.apache.solr.util.DistanceUnits) SolrException(org.apache.solr.common.SolrException) PrefixTreeStrategy(org.apache.lucene.spatial.prefix.PrefixTreeStrategy) AbstractSpatialPrefixTreeFieldType(org.apache.solr.schema.AbstractSpatialPrefixTreeFieldType)

Aggregations

DistanceUnits (org.apache.solr.util.DistanceUnits)2 ValueSource (org.apache.lucene.queries.function.ValueSource)1 DoubleConstValueSource (org.apache.lucene.queries.function.valuesource.DoubleConstValueSource)1 MultiValueSource (org.apache.lucene.queries.function.valuesource.MultiValueSource)1 VectorValueSource (org.apache.lucene.queries.function.valuesource.VectorValueSource)1 SpatialStrategy (org.apache.lucene.spatial.SpatialStrategy)1 HeatmapFacetCounter (org.apache.lucene.spatial.prefix.HeatmapFacetCounter)1 PrefixTreeStrategy (org.apache.lucene.spatial.prefix.PrefixTreeStrategy)1 SpatialArgs (org.apache.lucene.spatial.query.SpatialArgs)1 SolrException (org.apache.solr.common.SolrException)1 NamedList (org.apache.solr.common.util.NamedList)1 AbstractSpatialPrefixTreeFieldType (org.apache.solr.schema.AbstractSpatialPrefixTreeFieldType)1 FieldType (org.apache.solr.schema.FieldType)1 RptWithGeometrySpatialField (org.apache.solr.schema.RptWithGeometrySpatialField)1 SchemaField (org.apache.solr.schema.SchemaField)1 SpatialRecursivePrefixTreeFieldType (org.apache.solr.schema.SpatialRecursivePrefixTreeFieldType)1 SyntaxError (org.apache.solr.search.SyntaxError)1 SpatialContext (org.locationtech.spatial4j.context.SpatialContext)1 Point (org.locationtech.spatial4j.shape.Point)1 Shape (org.locationtech.spatial4j.shape.Shape)1