제품

실용적인 BM25 - 제1부: Elasticsearch에서 샤드가 정확도 점수에 미치는 영향

이것은 유사성 순위(정확도)에 대해 3부작으로 구성된 Practical BM25 시리즈의 첫 번째 게시물입니다. 다음 게시물은 하단에 링크되어 있습니다.

배경 Elasticsearch 5.0 에서 당사는 기본 유사성 알고리즘 을 Okapi BM25 로 변경했습니다. 이 알고리즘은 쿼리 작업과 관련된 결과의 점수를 매기는 데 사용됩니다. 이 블로그에서 BM25와 다른 측정 방식의 차이를 깊이 다루지는 않겠지만, BM25의 이론적 근거에 대한 소개가 필요하다면 Elastic 2016에서 발표된 BM25 Demystified 프레젠테이션을 시청해 보시기 바랍니다. 대신, 이 글에서는{ON} 사용 가능한 매개변수와 점수에 영향을 미치는 요소를 포함하여 BM25의 실질적인 사용법을 다루고(그리고 명확히 설명해 드리고)자 합니다.

이 블로그는 주로 텍스트 문서의 스코어링을 수행하는 사용자를 대상으로 한다는 점을 유념해 주십시오. 즉, 이 블로그는 검색 사용자를 돕는 데 중점을 두고 있습니다. 로그나 메트릭을 색인하고 타임스탬프와 같은 명시적인 메타데이터/숫자 순서로 정렬된 결과를 반환하는 경우, 이 블로그는 단순히 호기심을 충족하는 정도의 정보가 될 수 있습니다.

샤드가 점수에 미치는 영향 이해하기

집에서 직접 따라 해 보시길 바라며, 가장 먼저 해결해야 할 사항 중 하나는 샤드가 1개 이상일 때 점수에 어떤 영향을 미치는지 이해하는 것입니다. Elasticsearch는 기본적으로 인덱스당 5개의 기본 샤드를 사용하기 때문입니다. 먼저 “people”이라는 인덱스를 생성해 보겠습니다. 여기서 제공하는 설정은 기본값이므로 정의할 필요가 없지만, 데모를 위해 명시적으로 설정하겠습니다. 여기서는 제 이름(“Shane Connelly”)의 변형을 사용하겠지만, 직접 따라 하시는 경우 원하는 이름으로 자유롭게 바꾸셔도 됩니다.

PUT people
{
  "settings": {
    "number_of_shards": 5,
    "index" : {
        "유사성" : {
          "기본값" : {
            "type" : "BM25"
          }
        }
    }
  }
}

이제 도큐먼트를 추가하고 검색해 보겠습니다. 먼저, 제 이름을 추가하겠습니다:

PUT /people/_doc/1
{
  "title": "Shane"
}
GET /people/_doc/_search
{
    "query": {
        "match": {
             "title": "Shane"
         }
      }
}

이 시점에서 1개의 히트를 얻게 되며, 점수는 0.2876821입니다. 이 점수가 어떻게 도출되는지는 잠시 후에 자세히 살펴보겠지만, 먼저 제 전체 이름의 다른 변형이 포함된 문서를 몇 개 더 추가하면 어떤 일이 발생하는지 살펴보겠습니다.

PUT /people/_doc/2
{
  "title": "Shane C"
}
PUT /people/_doc/3
{
  "title": "Shane Connelly"
}
PUT /people/_doc/4
{
  "title": "Shane P Connelly"
}

이제 동일한 검색을 다시 수행하십시오:

GET /people/_doc/_search
{
    "query": {
        "match": {
             "title": "Shane"
         }
      }
}

이 시점에서 실제로 4개의 히트(hits)가 있어야 하지만, 점수를 보면 의아할 수 있습니다. 문서 1과 3은 모두 0.2876821의 점수를 가지지만, 문서 2는 0.19856805, 문서 4는 0.16853254의 점수를 가집니다. 이는 종종 새로운 사용자(사용자)를 당황하게 만드는 부분입니다. 문서 2와 3은 매우 유사합니다. 두 문서 모두 2개의 단어를 포함하고 “shane”과 일치하지만, 문서 2의 점수가 훨씬 낮습니다. “C”의 점수 산정과 “Connelly”의 점수 산정에 차이가 있다고 생각할 수 있지만, 사실 이는 문서가 샤드에 어떻게 배치되었는지와 관련이 있습니다.

참고로, Elasticsearch는 문서를 샤드로 나누며, 각 샤드는 데이터의 일부를 보유합니다. 다음을 살펴보면:

GET /_cat/샤드/people?v

이를 실행하면 샤드 2에는 2개의 문서가 있고 샤드 3과 4에는 1개의 문서만 있는 것을 확인할 수 있습니다(샤드 0과 1에는 아직 문서가 없습니다). 이는 “shane”이라는 용어의 총 발생 횟수가 이들 샤드마다 다르다는 것을 의미하며, 결과적으로 이 경우 점수 차이를 유발하는 원인이 됩니다. 기본적으로 Elasticsearch는 샤드 단위로 점수를 계산합니다.

사용자가 인덱스에 문서를 몇 개만 로드하기 시작하면서 “왜 문서 A가 문서 B보다 점수가 높거나 낮은가?”라고 질문하는 경우가 있는데, 그에 대한 답변은 사용자의 샤드 대 문서 비율이 상대적으로 높아 샤드 간에 점수가 왜곡되었기 때문인 경우가 있습니다. 샤드 간에 더 일관된 점수를 얻는 몇 가지 방법은 다음과 같습니다.

  1. 인덱스에 로드하는 문서가 많을수록 샤드의 용어 통계가 더 정규화됩니다. 충분한 문서가 있으면 각 샤드의 용어 통계 및 그에 따른 점수 산정의 미세한 차이를 느끼지 못할 수 있습니다.
  2. 더 낮은 샤드 수를 사용하여 용어 빈도의 통계적 편차를 줄일 수 있습니다. 예를 들어, 인덱스 설정에서 number_of_shards 를 1 로 설정했다면 점수가 매우 다르게 나타났을 것입니다. 문서 1은 0.13245322점, 문서 2와 3은 각각 0.105360515점, 문서 4는 0.0874691점을 기록했을 것입니다. 기본 샤드 수를 다르게 설정하는 데에는 몇 가지 장단점이 있으며, 이에 대해서는 정량적 클러스터 사이징 웨비나에서 다룹니다.
  3. 요청에 ?search_type=dfs_query_then_fetch 를 추가할 수 있습니다. 이 요청은 먼저 분산된 용어 빈도(DFS = Distributed Frequency Search)를 수집한 다음 이를 사용하여 점수를 계산합니다. 사실, 이는 샤드가 1개만 있을 때와 동일한 점수를 반환합니다. “search_type” 매개변수 사용 여부에 따라 결과가 어떻게 다른지 확인해 보십시오:
    GET /people/_doc/_search?search_type=dfs_query_then_fetch
    {
        "query": {
            "match": {
                 "title": "Shane"
             }
          }
    }
    이는 number_of_shards=1을 설정한 것과 동일한 결과를 제공합니다. 그렇다면 “더 정확한 점수를 산출한다면 왜 기본적으로 활성화되어 있지 않은가?”라는 의문이 들 수 있습니다. 그에 대한 답은 모든 통계를 수집하기 위해 처리 과정 중에 추가적인 왕복(round trip)이 발생하며, 일부 사용 사례(속도가 점수 정확도보다 중요하지 않은 경우)에서는 이 왕복이 불필요하다는 것입니다. 또한 샤드에 충분한 데이터가 있으면 통계가 서로 매우 비슷해질 수 있으므로 왕복 과정 또한 불필요해집니다. 데이터가 충분한 경우, search_type=dfs_query_then_fetch 는 일부 사용자 지정 라우팅의 경우와 같이 샤드 간 데이터가 계속해서 불균등하게 분산되어 있을 때만 주로 필요합니다.

이제 샤딩이 점수에 어떤 영향을 미칠 수 있는지(그리고 이를 조정하는 방법)에 대해 이해했습니다. 다음으로 BM25 알고리즘을 살펴보고 다양한 변수가 어떻게 작용하는지 알아보겠습니다.

이 시리즈를 계속 보려면 다음을 확인하세요: 2부: BM25 알고리즘과 변수