2014-09-05 46 views
4

我有一項任務,不僅可以通過索引文檔的字符串字段的相關性對搜索結果進行排序,也可以通過從給定地理點到與每個索引文檔相關的點的距離進行排序。應該提到的是,只有前十個左右匹配的文檔應該包含在結果集中。按精確距離排序並不重要,只有給定點的「距離水平」纔是重要的。Lucene地理距離排序性能

從技術上講,我已經成功實施了這項任務。任務的地理部分被實現爲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項進行排序。如果沒有其他幫助,我會選擇這種方式。

但我的問題是是否存在更適當的解決方案。也許我能以某種方式將結果項目按等效類別(具有相同或相似的分數)進行拆分,並將地理空間排序僅應用於前幾個類別?請建議。

回答

1

看看elasticsearch如何在function_score查詢中實現這一點。你可以重複使用他們所做的一些事情。如果我沒有記錯的話,他們可以選擇使用更快但更不準確的距離計算算法。你可能想要做類似的事情。

+0

好的,謝謝!我要評估這種可能性,然後寫一個答案,並批准你的答案,希望在一天左右。 – user3159253 2014-09-08 05:11:25

0

我在使用其他CustomScoreProvider爲DistanceQuery:

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從Sorting by Distanceplane距離函數implementation較慢,比上述代碼功能customScore。此功能是基於文章Geographic distance can be simple and fast

user3159253實現的,也許您有此線程的答案?