繁体   English   中英

Lucene地理距离排序性能

[英]Lucene geo-distance sorting performance

我的任务是不仅通过索引文档的字符串字段的相关性来对搜索结果进行排序,而且还通过从给定地理点到与被索引的每个文档相关联的点的距离来对搜索结果进行排序。 应该提到的是,结果集中只应包含前十个匹配的文档。 按精确距离排序并不重要,只有给定点的“距离水平”很重要。

从技术上讲,我已成功实施了该任务。 任务的地理部分是作为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倍。

但是,当我从测试切换到真实数据库时,索引中的文档数量从一千个增加到大约一千万个,并且将会增加更多(在不久的将来估计有一亿个),然后情况发生了巨大变化。 实际上我不能再得到任何搜索结果,因为JVM内存和处理器都没用了。 目前它无法使用-Xmx6g以及更多内容在JVM中完成搜索。 当然,我可以为任务购买更好的硬件,但问题可能通过选择更合适的排序策略来解决。

一种解决方案是完全避免Lucene提供的地理排序,并在项目相关性得分相似时手动对结果集的前N个项目进行排序。 如果没有别的办法,我会选择这种方式。

但我的问题是,是否存在更充分的解决方案。 也许我可以通过某种方式按等效类别(具有相同或相似的足够分数)来分割结果项目,并仅对前几个类别应用地理空间排序? 请建议。

看看elasticsearch在function_score查询中如何实现它。 您可以重复使用他们所做的一些事情。 如果我没记错的话,他们也可以选择使用更快但不太精确的距离计算算法。 你可能想做类似的事情。

我正在为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,也​​许你有这个帖子的答案?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM