Lucene地理距离排序性能

4
我有一个任务,需要对搜索结果进行排序,不仅要按照索引文档的字符串字段相关性排序,还要按照从给定地理点到与每个被索引文档关联的点的距离排序。需要注意的是,只有前十个或更少匹配的文档应包含在结果集中。此外,精确距离排序并不重要,只有从给定点出发的“距离级别”才重要。
技术上,我已经成功实现了这个任务。任务中的地理部分是作为一个CustomScoreQuery派生类实现的:
private static class DistanceQuery extends CustomScoreQuery {

  public DistanceQuery(final Query _subQuery, final SpatialStrategy _strategy, final Point _bp) {
    super(_subQuery, new FunctionQuery(_strategy.makeDistanceValueSource(_bp)));
  }

  @Override
  protected CustomScoreProvider getCustomScoreProvider(AtomicReaderContext _context) throws IOException {
    return new CustomScoreProvider(_context) {
      @Override
      public float customScore(int _doc, float _subQueryScore, float _valSrcScore) throws IOException {
        // the spatial strategies makeDistanceValueSource creates a ValueSource which score varies from almost 0 for nearby points to 2.7-2.8 for distant points
        // so I voluntarily chosen 2 as the normalization factor and increase subQueryScore for that factor at max;
        logger.debug("customScore for document {}: [subQuery={}, valScore={}", this.context.reader().document(_doc).getField(IndexedField.id.name()).numericValue().toString(), _subQueryScore, _valSrcScore);
        return (_valSrcScore > 2 || _valSrcScore < 0) ? _subQueryScore : _subQueryScore + (2 - _valSrcScore);
      }
    };
  }
}

并使用这种地理空间的“增强”来包装给定的“文本”查询。
一般而言,所选择的策略给出了相当合理的结果。正如人们可能看到的那样,最终分数仅略高于初始查询分数(最多高2分)。对于具有十几个以上得分的典型结果分数,这种地理空间的添加只是在“后排序”否则相似的文档方面起作用。
在索引中有数百或数千个测试文档时,打包查询的性能也足够好。每次搜索大约需要10-50毫秒,这只比未封装的查询慢2-5倍。
但是,当我从测试转向真实的数据库,并且索引中的文档数量从一千增加到近1000万,并且将进一步增加(估计将来会达到1亿),那么情况发生了巨大变化。实际上,我无法再获得任何搜索结果,因为JVM耗尽了内存和处理器。目前,在-Xmx6g及更高版本的JVM中无法完成搜索。 当然,我可以为此任务购买更好的硬件,但是通过选择更适当的排序策略可能会解决问题。
一种解决方案是完全避免Lucene提供的地理排序,如果项目相关性得分相似,则手动排序结果集的前N项。如果没有其他帮助,我将选择这种方式。
但我的问题是是否存在更合适的解决方案。也许我可以通过等价类(得分相同或足够相似)对结果项进行分类,并仅将地理空间排序应用于前几个类别?请给出建议。
2个回答

1
看看elasticsearch如何在function_score查询中实现这一点。您可能可以从他们所做的事情中重复使用一些内容。如果我记得正确,他们可以选择使用更快但不太准确的距离计算算法。您可能希望做类似的事情。

好的,谢谢!我会评估这种可能性,然后会在一天左右写出回复并批准你的答案。 - user3159253

0

我正在为DistanceQuery使用另一个CustomScoreProvider:

public class DistanceQueryScoreProvider extends CustomScoreProvider {

    private double x;
    private double y;

    public DistanceQueryScoreProvider(LeafReaderContext context, double x, double y) {
        super(context);
        this.x = x;
        this.y = y;
    }

    @Override
    public float customScore(int doc, float subQueryScore, float valSrcScore) throws IOException {
        Document d = context.reader().document(doc);
        double geomX = d.getField(Consts.GEOM_X_FIELD).numericValue().doubleValue();
        double geomY = d.getField(Consts.GEOM_Y_FIELD).numericValue().doubleValue();
        double deglen = 110.25;
        double deltaX = geomY - y;
        double deltaY = (geomX - x) * Math.cos(y);
        return -Double.valueOf(deglen * Math.sqrt(deltaX * deltaX + deltaY * deltaY)).floatValue();
    }
}

Elasticsearch实现的plane距离函数(实现)按距离排序的速度比上述代码函数customScore要慢。该函数是基于文章地理距离可以简单快速计算实现的。

user3159253,也许你对这个主题有答案?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接