Reference/How To ...

3. Getting consistent scoring

drscg 2018. 10. 5. 18:01

The fact that Elasticsearch operates with shards and replicas adds challenges when it comes to having good scoring.

Elasticsearch가 shard, relpica와 함께 동작한다는 사실은 score 계산에 어려움이 있다는 것을 의미한다.

Scores are not reproducible

Say the same user runs the same request twice in a row and documents do not come back in the same order both times, this is a pretty bad experience isn’t it? Unfortunately this is something that can happen if you have replicas (index.number_of_replicas is greater than 0). The reason is that Elasticsearch selects the shards that the query should go to in a round-robin fashion, so it is quite likely if you run the same query twice in a row that it will go to different copies of the same shard.

동일한 사용자가 동일한 request를 두 번 연속으로 했을 때, 양쪽의 document가 동일한 순서로 나오지 않는다고 가정해 보면, 이는 굉장히 나쁜 경우일 것이다. 불행하게도 이런 상황은 replica를 가지고 있을 경우(index.number_of_replicas 가 0보다 큰 경우) 발생할 수 있다. 그 이유는 Elasticsearch가 query를 실행할 shard를 round-robin 방식으로 선택하기 때문에, 동일한 query를 두 번 연속으로 하면, 동일한 shard의 다른 복사본으로 가는 경우가 많기 때문이다. 

Now why is it a problem? Index statistics are an important part of the score. And these index statistics may be different across copies of the same shard due to deleted documents. As you may know when documents are deleted or updated, the old document is not immediately removed from the index, it is just marked as deleted and it will only be removed from disk on the next time that the segment this old document belongs to is merged. However for practical reasons, those deleted documents are taken into account for index statistics. So imagine that the primary shard just finished a large merge that removed lots of deleted documents, then it might have index statistics that are sufficiently different from the replica (which still have plenty of deleted documents) so that scores are different too.

이게 왜 문제인가? index 통계는 score에 있어 아주 중요하다. 그리고, 이들 index 통계는 삭제된 document로 인해 동일한 shard의복사본간에 다를 수도 있다. 알다시피, document가 삭제되거나 업데이트되면, 기존의 dcoument는 index에서 즉시 삭제되지 않고, 단지 삭제된 것으로 표시되고, 이 기존 document가 포함된 segmemt가 병합된 후에 disk에서 제거될이다. 그러나 현실적인 이류로 인해, 이들 삭제된 document는 index 통계가 고려된다. primary shard가 방금 많은 삭제된 document를 제거한 큰 병합을 완료했다면, replica(여전히 많은 양의 삭제된 document를 가진)와 완전히 다른 index 통계를 가지므로, score 또한 다르다.

The recommended way to work around this issue is to use a string that identifies the user that is logged is (a user id or session id for instance) as a preference. This ensures that all queries of a given user are always going to hit the same shards, so scores remain more consistent across queries.

이를 해결하기 위해 권장되는 방법은 logon한 사용자룰 삭별하는 문자열(user id 또는 session id)을 preference 로 사용하는 것이다. 이렇게 하면, 해당 사용자의 모든 query가 항상 동일한 shard로 가게되므로, score는 query에 대해 일관성을 가지게 된다.

This work around has another benefit: when two documents have the same score, they will be sorted by their internal Lucene doc id (which is unrelated to the _id or _uid) by default. However these doc ids could be different across copies of the same shard. So by always hitting the same shard, we would get more consistent ordering of documents that have the same scores.

이렇게 하면 또 다른 장점이 있다. 2개의 document가 동일한 score를 가질 경우, 기본적으로 내부 Lucene doci id(_id 나 _uid 와 관련이 없는)로 정렬된다. 그러나 이들 doc id는 동일한 shard의 복사본간에 서로 다를 수 있다. 그래서, 동일한 shard로 가면, 동일한 score를 가진 document를 더 일관되게 정렬할 수 있다.

Relevancy looks wrong

If you notice that two documents with the same content get different scores or that an exact match is not ranked first, then the issue might be related to sharding. By default, Elasticsearch makes each shard responsible for producing its own scores. However since index statistics are an important contributor to the scores, this only works well if shards have similar index statistics. The assumption is that since documents are routed evenly to shards by default, then index statistics should be very similar and scoring would work as expected. However in the event that you either:

동일한 내용을 가진 2개의 document가 다른 score를 가지거나 exact match가 먼저 나오지 않는다면, 그 문제는 shard와 관련이 있을 수 있다. 기본적으로, Elasticsearch에서는 각 shard가 각자의 score를 산출하도록 되어 있다. 그러나, index 통계는 score에 중요한 요인이기 때문에, shard가 비슷한 index 통계를 가질 경우에만 이 방법이 효과적이다. document는 기본적으로 shard에 고르게 route되므로, index 통계는 매우 비슷하며 score 계산은 예상대로 동작할 것이다. 그러나 다음과 같은 경우에는

  • use routing at index time
    index시에 route를 사용하거나
  • query multiple indices
    다수의 index를 query하거나
  • or have too little data in your index
    index에 data가 아주 적을 경우

then there are good chances that all shards that are involved in the search request do not have similar index statistics and relevancy could be bad.

search request와 관련된 모든 shard가 비슷한 index 통계를 가지지 않고, relevancy가 좋지 않을  수 있다.

If you have a small dataset, the easiest way to work around this issue is to index everything into an index that has a single shard (index.number_of_shards: 1). Then index statistics will be the same for all documents and scores will be consistent.

data가 작을 경우, 이 문제를 해결하는 가장 쉬운 방법은 모든 data를 하나의 shard를 가지는 index(index.number_of_shards: 1)에 index하는 것이다.  그러면 index 통계는 모든 document에 대해 동일할 것이고 score도 일관성이 있을 것이다.

Otherwise the recommended way to work around this issue is to use the dfs_query_then_fetchsearch type. This will make Elasticsearch perform an inital round trip to all involved shards, asking them for their index statistics relatively to the query, then the coordinating node will merge those statistics and send the merged statistics alongside the request when asking shards to perform the query phase, so that shards can use these global statistics rather than their own statistics in order to do the scoring.

그렇지 않으면, 이 문제를 해결하기 위해 dfs_query_then_fetch search type을 사용하는 것이 좋다. 이렇게 하면 Elasticsearch는 모든 관련 shard에 대해 기본적인 round trip을 사용하여, 해당 shard에 query에 해당하는 index 통계를 요구한 다음, coordinating node는 shard에게 query 절을 수행하도록 요청할 때, 해당 통계를 병합하고, 병합된 통계를 request와 함께 전송하여, shard가 score를 계산하기 위해 자체 통계가 아닌 전체 통계를 사용하도록 할 수 있다.

In most cases, this additional round trip should be very cheap. However in the event that your query contains a very large number of fields/terms or fuzzy queries, beware that gathering statistics alone might not be cheap since all terms have to be looked up in the terms dictionaries in order to look up statistics.

대부분의 경우, 이 추가적인 round trip은 비용은 매우 저렴하다. 그러나 query가 매우 많은 field/terms를 가지고 있을 경우, 통계를 조회하기 위해 모든 terms를 terms dictionary에서 조회해야 하므로, 통계 수집 비용은 저렴하지 않을 수도 있다.

'Reference > How To ...' 카테고리의 다른 글

5. Tune for search speed  (0) 2018.10.05
4. Tune for indexing speed  (0) 2018.10.05
2. Mixing exact search with stemming  (0) 2018.10.05
1. General recommendations  (0) 2018.10.05
How to  (0) 2018.10.05