Hybrid 쿼리

Hybrid 쿼리

hybrid 쿼리는 여러 쿼리의 관련성 점수를 주어진 문서에 대한 하나의 점수로 결합할 수 있어요. 하나 이상의 쿼리 목록을 포함하며 각 하위 쿼리에 대해 샤드 수준에서 문서 점수를 독립적으로 계산합니다.

출처: 문서

본문

hybrid 쿼리를 사용하면 여러 쿼리의 관련성 점수를 주어진 문서에 대한 하나의 점수로 결합할 수 있어요. hybrid 쿼리는 하나 이상의 쿼리 목록을 포함하며 각 하위 쿼리에 대해 샤드 수준에서 문서 점수를 독립적으로 계산해요. 중복 계산을 피하기 위해 하위 쿼리 재작성(rewriting)은 코디네이팅 노드 수준에서 수행돼요.

예시 (Example)

hybrid 쿼리 사용법은 Hybrid search의 단계를 따라 배울 수 있어요. 종합적인 예시는 Getting started with semantic and hybrid search를 따르세요.

파라미터 (Parameters)

다음 표는 hybrid 쿼리가 지원하는 모든 최상위 파라미터를 나열해요.

파라미터 설명
queries 문서를 매칭하는 데 사용되는 하나 이상의 쿼리 절 배열. 문서는 결과에 반환되기 위해 적어도 하나의 쿼리 절과 일치해야 해요. 검색 파이프라인을 적용해 모든 쿼리 절의 관련성 점수를 하나의 점수로 결합해요. 최대 쿼리 절 수는 5개예요. 필수.
filter hybrid 쿼리의 모든 하위 쿼리에 적용할 필터. 필터는 단일 쿼리 객체여야 해요. 여러 필터 조건을 적용하려면 Boolean 쿼리로 결합하세요. 자세한 내용은 Hybrid search with pre-filtering을 참조하세요.
pagination_depth 각 하위 쿼리가 각 샤드에서 반환하는 최대 검색 결과 수. 이 값은 검색 파이프라인이 정규화하고 결합하는 문서 집합을 제한하므로, 페이지를 매길 수 있는 깊이와 결과 순서 모두에 영향을 줘요. 유효한 값은 1부터 index.max_result_window 값(기본값 10000)까지의 정수예요. from이 0보다 크면 필수이고, 그렇지 않으면 선택 사항이에요. 제공하지 않으면 각 하위 쿼리는 각 샤드에서 최대 size만큼의 결과를 반환해요. 자세한 내용은 Paginating hybrid query results를 참조하세요.

Hybrid 쿼리 재점수화 (Rescoring hybrid queries)

2.18 버전에서 도입되었어요.

hybrid 쿼리에서는 rescore 파라미터를 사용할 수 있어요. 하지만 재점수화는 표준 쿼리와 비교해 hybrid 쿼리에서 다르게 동작해요.

표준 쿼리에서는 모든 샤드의 결과가 병합된 후 코디네이팅 노드에서 재점수화가 적용돼요. hybrid 쿼리에서는 정규화 및 결합 파이프라인이 실행되기 전에 각 하위 쿼리의 결과에 재점수화가 샤드 수준에서 독립적으로 적용돼요.

hybrid 쿼리의 재점수화 처리 순서는 다음과 같아요.

  1. hybrid 쿼리의 각 하위 쿼리가 샤드에서 실행되어 별도의 결과 집합을 생성해요.
  2. rescore 쿼리가 각 하위 쿼리의 결과에 독립적으로 적용돼요.
  3. 재점수화된 결과가 코디네이팅 노드로 전송돼요.
  4. 검색 파이프라인(정규화 프로세서 또는 점수 랭커 프로세서)이 재점수화된 하위 쿼리 점수를 정규화하고 결합해요.

hybrid 쿼리에서 재점수화를 사용할 때는 다음 사항을 주의하세요.

  • window_size는 결합된 결과가 아니라 각 하위 쿼리의 결과에 개별적으로 적용돼요.
  • 재점수화와 함께 명시적 정렬을 사용할 수 없어요. hybrid 검색에서 정렬과 rescore 쿼리를 결합하려 하면 OpenSearch는 오류를 반환해요.
  • 재점수화는 정규화 프로세서와 점수 랭커 프로세서가 지원하는 모든 점수 기반 및 순위 기반 정규화·결합 기법과 호환돼요.

다음 예시는 두 필드에 걸쳐 키워드 매칭을 결합한 hybrid 검색에서 정확한 구문 "search engine"을 포함한 문서를 부스트하기 위해 match_phrase rescore 쿼리를 사용해요.

POST /my-index/_search?search_pipeline=nlp-search-pipeline
{
  "query": {
    "hybrid": {
      "queries": [
        {
          "match": {
            "title": "search engine"
          }
        },
        {
          "match": {
            "description": "search engine"
          }
        }
      ]
    }
  },
  "rescore": {
    "window_size": 50,
    "query": {
      "rescore_query": {
        "match_phrase": {
          "title": {
            "query": "search engine",
            "slop": 2
          }
        }
      },
      "query_weight": 0.7,
      "rescore_query_weight": 1.2
    }
  }
}

응답에는 초기 hybrid 쿼리 매칭과 rescore 부스트를 모두 반영한 점수를 가진 문서가 포함돼요.

{
  "took": 30,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 0.95,
    "hits": [
      {
        "_index": "my-index",
        "_id": "1",
        "_score": 0.95,
        "_source": {
          "title": "Building a search engine",
          "description": "A guide to modern search engine architecture"
        }
      },
      {
        "_index": "my-index",
        "_id": "2",
        "_score": 0.67,
        "_source": {
          "title": "Introduction to search",
          "description": "Learn about search engine basics"
        }
      },
      {
        "_index": "my-index",
        "_id": "3",
        "_score": 0.42,
        "_source": {
          "title": "Database engine tuning",
          "description": "How to optimize your search queries"
        }
      }
    ]
  }
}

이 예시에서 문서 1은 rescore match_phrase 쿼리가 점수를 부스트하므로(제목 필드에 정확한 구문 "search engine"이 포함됨) 가장 높게 순위가 매겨져요. 문서 2는 해당 구문이 description 필드에만 있어서 title에 대한 구문 매칭으로 받는 부스트가 더 작아요. 문서 3은 여러 필드에 걸쳐 개별 용어 "search"와 "engine"은 일치하지만 정확한 구문은 아니므로 가장 작은 부스트를 받아요. rescore 쿼리가 정규화 전에 각 하위 쿼리 결과에 샤드 수준에서 독립적으로 적용되므로, 구문 부스트가 최종 결합 점수에 영향을 줘요.

Hybrid 쿼리에서의 min_score 지원

  • 3.5 버전부터 min_score 파라미터는 점수 정규화와 결합 이후에 적용돼요. _score로 정렬하거나 명시적 정렬 순서를 지정하지 않았을 때만 사용할 수 있어요. min_score를 다른 정렬 기준과 함께 사용하면 요청이 오류가 돼요.
  • OpenSearch 3.5부터 512개 이상의 샤드를 가진 인덱스에서 hybrid 쿼리를 사용할 수 있어요. OpenSearch는 모든 샤드에서 적절한 점수 정규화를 보장하기 위해 배치 감소(batched reduction)를 자동으로 비활성화해요. 구성은 필요 없어요. 샤드 수가 많은 인덱스에서는 코디네이팅 노드의 메모리 사용량이 더 높을 수 있음에 유의하세요. _msearch 엔드포인트는 배치 감소의 자동 처리를 지원하지 않아요. 많은 샤드에 걸친 hybrid 쿼리가 있는 다중 검색 요청에는 인덱스 패턴 또는 별칭과 함께 _search 엔드포인트를 사용하세요.

제한 사항 (Limitations)

hybrid 쿼리는 검색 요청의 최상위 쿼리로 설계되었어요. function_score, constant_score, script_score, boosting 같은 다른 복합 또는 래퍼 쿼리 안에 중첩할 수 없어요. 이 제한은 다중 수준 중첩에도 적용돼요. 예를 들어 hybrid 쿼리를 포함하는 function_score 쿼리를 담은 bool 쿼리는 허용되지 않아요. 이런 래퍼 쿼리 안에 hybrid 쿼리를 중첩하면 런타임 오류가 발생하거나 정규화 파이프라인을 조용히 우회할 수 있어요.

hybrid 쿼리는 래퍼 쿼리와 호환되지 않는 특수한 점수 산정 메커니즘을 사용해요. 래퍼 쿼리는 정규화·결합 파이프라인이 올바르게 작동하는 데 필요한 hybrid 쿼리의 하위 쿼리별 점수 수집을 우회하는 다른 내부 스코어러를 사용해요.

hybrid 검색 결과에 점수 부스트 함수를 적용하려면 hybrid 쿼리를 bool 쿼리로 바꾸고 하위 쿼리들을 should 절로 이동하세요. 이 대안은 hybrid 쿼리를 지원하는 모든 OpenSearch 버전에서 작동해요.

예를 들어 다음 쿼리는 지원되지 않아요.

GET /my-index/_search?search_pipeline=my-pipeline
{
  "query": {
    "function_score": {
      "query": {
        "hybrid": {
          "queries": [
            {"match": {"title": "search terms"}},
            {"term": {"category": "books"}}
          ]
        }
      },
      "functions": [{"field_value_factor": {"field": "popularity"}}]
    }
  }
}

대신 다음 동등한 쿼리를 사용하세요.

GET /my-index/_search
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "should": [
            {"match": {"title": "search terms"}},
            {"term": {"category": "books"}}
          ]
        }
      },
      "functions": [{"field_value_factor": {"field": "popularity"}}]
    }
  }
}

hybrid 쿼리 대신 should 절을 포함한 bool 쿼리를 사용하면 검색 파이프라인의 정규화·결합 프로세서는 적용되지 않아요. 대신 하위 쿼리의 점수는 표준 Boolean 점수 산정(일치 절의 합)으로 결합돼요. 그런 다음 function_score 함수가 결합된 점수에 적용돼요.

Hybrid 쿼리 비활성화 (Disabling hybrid queries)

기본적으로 hybrid 쿼리는 활성화되어 있어요. 클러스터에서 hybrid 쿼리를 비활성화하려면 opensearch.yml에서 plugins.neural_search.hybrid_search_disabled 설정을 true로 설정하세요.

더 알아보기 (Learn more)