<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Sachin Frayne - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Sachin Frayne - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/kr/search-labs/author/sachin-frayne</link>
    </image>
    <link>https://www.elastic.co/kr/search-labs/author/sachin-frayne</link>
    <atom:link href="https://www.elastic.co/kr/search-labs/rss/author/sachin-frayne.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[kr]]></language>
    <lastBuildDate>Mon, 14 Sep 2026 18:33:55 GMT</lastBuildDate>
  <item>
    <title><![CDATA[OpenSearch보다 최대 8배 빠른 Elasticsearch 벡터 검색]]></title>
    <description><![CDATA[OpenSearch와 Elasticsearch의 필터링된 벡터 검색 벤치마크를 비교하고, 컨텍스트 엔지니어링 시스템에서 벡터 검색 성능이 중요한 이유를 살펴봅니다.]]></description>
    <content:encoded><![CDATA[<h2>AI 에이전트와 컨텍스트 엔지니어링에서 검색 속도가 중요한 이유</h2><p>문서 코퍼스 2,000만 개에 대한 벤치마크에서 Elasticsearch는 필터링된 벡터 검색에서 OpenSearch 대비 최대 8배 높은 처리량을 제공하는 동시에, 테스트한 모든 구성에서 더 높은 Recall@100을 달성했습니다. 컨텍스트 엔지니어링에는 빠른 벡터 검색 이상이 필요합니다. 워크플로우가 반복되면서 하이브리드 검색 및 필터링과 같은 강력한 관련성 제어, 운영 간소화, 예측 가능한 성능이 필요합니다. 그러나 에이전트가 요청당 검색, 추론, 검색 루프를 여러 번 실행하는 경우가 많기 때문에 검색 지연 시간이 배가되므로, 이 문제를 개선하면 엔드투엔드 응답성 향상과 비용 절감 효과를 누릴 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9daec868eed84658/6a170bef6234e0c322db1a19/d5a52a07773f0942c2baa732dacfe782aac0f415-1600x683.png" alt="OpenSearch와 Elasticsearch 비교: 필터링된 벡터 검색 벤치마크 처리량" /><p>컨텍스트 엔지니어링에서 검색은 일회성 단계가 아닙니다. 에이전트와 애플리케이션은 검색 → 추론 → 검색과 같은 루프를 반복적으로 실행해 쿼리를 정제하고, 사실을 검증하며, 근거 있는 컨텍스트를 조립하고, 작업을 완료합니다. 이 패턴은 에이전트 워크플로우와 반복 Retrieval-Augmented Generation(RAG)에서 흔히 볼 수 있습니다. 사용자 요청당 검색이 여러 번 호출될 수 있으므로 응답 시간이 지연되거나 인프라 비용이 증가할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt718c72fb858e4c98/6a170bf00e2e496e7241a132/54ac476ff20a3cf93484298c9ae47612c12fc110-800x417.png" alt="컨텍스트 엔지니어링은 대규모 컨텍스트 풀을 제한된 LLM 컨텍스트 창으로 환합니다." /><h2>벡터 검색 성능이 중요한 이유</h2><p></p><p>쇼핑 어시스턴트가 '15인치 노트북이 들어가고, 방수 기능이 있으며, 금요일까지 배송 가능한 6만원 이하의 기내용 백팩을 찾는다'는 질문에 답하는 경우를 생각해 보겠습니다.</p><p>실제 환경에서 어시스턴트가 벡터 쿼리를 한 번만 실행하고 멈추는 경우가 거의 없습니다. 올바른 컨텍스트를 구축하기 위해 검색 루프를 실행하는데, 각 단계는 일반적으로 가용성, 지역, 배송 예정일, 브랜드 규칙 및 정책 적합성과 같은 필터에 의해 제한을 받습니다.</p><p><strong>1단계: 의도를 해석해 제약 조건으로 변환</strong></p><p>에이전트는 요청을 다음과 같은 구조화된 필터와 의미론적 쿼리로 변환합니다.</p><ul><li><p>필터: 재고 있음, 사용자의 우편번호로 배송 가능, 금요일까지 배송, 가격 6만원 미만, 유효한 상품 목록</p></li><li><p>벡터 쿼리: '기내 반입 가능한 백팩, 15인치 노트북, 방수'</p></li></ul><p><strong>2단계: 후보를 검색한 후 정제</strong></p><p>우수한 일치 항목을 놓치지 않기 위해 종종 변형된 검색을 반복합니다.</p><ul><li><p>'노트북 슬리브가 포함된 기내용 백팩'</p></li><li><p>'통근용 방수 백팩 15인치'</p></li><li><p>'기내용 경량 백팩'</p></li></ul><p>관련성이 없거나 사용할 수 없는 항목을 검색하는 것은 컨텍스트 낭비이므로 각 쿼리는 동일한 자격 필터를 사용합니다.</p><p><strong>3단계: 위험을 줄이기 위해 확장하여 세부 정보 확인</strong></p><p>그런 다음 에이전트는 최종 답변에 영향을 미치는 주요 속성을 확인하기 위해 데이터를 다시 검색합니다.</p><ul><li><p>재질 및 방수 기능 관련 문구</p></li><li><p>치수 및 노트북 수납 공간 크기</p></li><li><p>반품 정책 또는 보증 제약 조건</p></li><li><p>재고가 부족한 경우 대체 옵션</p></li></ul><p>이것이 검색, 추론, 검색, 조립을 거치는 다단계 컨텍스트 엔지니어링입니다.</p><h2>컨텍스트 엔지니어링에서 지연 시간과 재현율이 중요한 이유</h2><p>이러한 상호작용은 사용자 세션당 수십 건의 필터링된 검색 호출을 포함할 수 있습니다. 따라서 통화당 지연 시간이 엔드투엔드 응답 시간에 직접적인 영향을 미치며, 재현율이 낮으면 에이전트가 추가 재시도를 하거나 적격 항목을 놓치게 되어 응답 품질이 저하됩니다.</p><p>요점: 컨텍스트 엔지니어링 시스템에서 필터링된 근사 이웃(ANN)은 일회성 조회로 끝나지 않습니다. 이는 제약 조건 하에서 반복되는 작업이므로, 대형 언어 모델(LLM)이 가장 중요한 구성 요소인 경우에도 벡터 검색 성능이 지연 시간, 처리량, 비용에 즉각적으로 영향을 미칩니다.</p><h2>벤치마킹</h2><h3>결과</h3><p>그래프 2에서 각 점은 하나의 테스트 구성을 나타냅니다. 지연 시간이 짧고 재현율이 높은 최상의 결과는 왼쪽 상단에 표시됩니다. Elasticsearch의 결과가 OpenSearch보다 지속적으로 왼쪽 상단에 가깝게 위치한다는 점에서 동일한 워크로드 설정에서 더 나은 속도와 정확도를 확인할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb562b30a600cc8e1/6a170bf2cf4f253582b2d1b2/c50d1df00968cac18149a2799e6242fbe49b66a0-1600x990.png" alt=" 그래프 2: 재현율 대 평균 지연 시간(재채점 1)." /><h4>주요 인사이트</h4><ul><li><p><code>s_n_r_value</code>: <code>size_numCandidates_rescoreOversample</code> 의 약어(k 및 numCandidates는 이러한 테스트에서 numCandidates와 동일하게 설정됨), 예를 들어 <code>100_500_1</code> 은 size=100, numCandidates=500 및 k=500, rescore oversample=1을 의미합니다.</p></li><li><p>재현율: 해당 구성에 대한 측정된 Recall@100</p></li><li><p>평균 지연 시간(ms): 쿼리당 평균 엔드투엔드 지연 시간</p></li><li><p>처리량: 초당 쿼리 수</p></li><li><p>재현율 %: Elasticsearch와 OpenSearch의 상대적 재현율 상승(Elasticsearch-OpenSearch)/OpenSearch</p></li><li><p>지연 시간 Xs: OpenSearch의 평균 지연 시간을 Elasticsearch의 평균 지연 시간으로 나눈 값</p></li><li><p>처리량 Xs: Elasticsearch 처리량을 OpenSearch 처리량으로 나눈 값</p></li></ul><p>엔진</p><p>`s_n_r_value`</p><p>재현율</p><p>평균 지연 시간(ms)</p><p>처리량</p><p>재현율 %</p><p>지연 시간 Xs</p><p>처리량 Xs</p><p>Elasticsearch</p><p>100_250_1</p><p>0.7704</p><p>25</p><p>534.75</p><p>9.70%</p><p>2.28</p><p>1.91</p><p>OpenSearch</p><p>100_250_1</p><p>0.7023</p><p>57.08</p><p>279.58</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_500_1</p><p>0.8577</p><p>25.42</p><p>524.14</p><p>7.20%</p><p>2.4</p><p>2</p><p>OpenSearch</p><p>100_500_1</p><p>0.8001</p><p>60.9</p><p>262.12</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_750_1</p><p>0.8947</p><p>29.67</p><p>528.09</p><p>5.72%</p><p>2.25</p><p>2.21</p><p>OpenSearch</p><p>100_750_1</p><p>0.8463</p><p>66.76</p><p>239.11</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_1000_1</p><p>0.9156</p><p>29.65</p><p>534.5</p><p>4.66%</p><p>2.46</p><p>2.44</p><p>OpenSearch</p><p>100_1000_1</p><p>0.8748</p><p>72.88</p><p>219.01</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_1500_1</p><p>0.9386</p><p>31.84</p><p>497.3</p><p>3.38%</p><p>2.71</p><p>2.68</p><p>OpenSearch</p><p>100_1500_1</p><p>0.9079</p><p>86.16</p><p>185.4</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_2000_1</p><p>0.9507</p><p>34.69</p><p>457.2</p><p>2.57%</p><p>2.98</p><p>2.96</p><p>OpenSearch</p><p>100_2000_1</p><p>0.9269</p><p>103.36</p><p>154.55</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_2500_1</p><p>0.9582</p><p>37.9</p><p>418.43</p><p>1.99%</p><p>3.28</p><p>3.26</p><p>OpenSearch</p><p>100_2500_1</p><p>0.9395</p><p>124.29</p><p>128.53</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_3000_1</p><p>0.9636</p><p>41.86</p><p>379.4</p><p>1.62%</p><p>3.46</p><p>3.44</p><p>OpenSearch</p><p>100_3000_1</p><p>0.9482</p><p>144.67</p><p>110.34</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_4000_1</p><p>0.9705</p><p>50.28</p><p>316.21</p><p>1.06%</p><p>3.87</p><p>3.85</p><p>OpenSearch</p><p>100_4000_1</p><p>0.9603</p><p>194.36</p><p>82.22</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_5000_1</p><p>0.9749</p><p>58.77</p><p>270.91</p><p>0.73%</p><p>4.43</p><p>4.41</p><p>OpenSearch</p><p>100_5000_1</p><p>0.9678</p><p>260.33</p><p>61.38</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_6000_1</p><p>0.9781</p><p>66.75</p><p>238.59</p><p>0.52%</p><p>4.91</p><p>4.89</p><p>OpenSearch</p><p>100_6000_1</p><p>0.973</p><p>327.44</p><p>48.81</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_7000_1</p><p>0.9804</p><p>74.64</p><p>213.49</p><p>0.38%</p><p>5.28</p><p>5.27</p><p>OpenSearch</p><p>100_7000_1</p><p>0.9767</p><p>394.24</p><p>40.53</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_8000_1</p><p>0.9823</p><p>82.28</p><p>193.59</p><p>0.27%</p><p>6.86</p><p>6.83</p><p>OpenSearch</p><p>100_8000_1</p><p>0.9797</p><p>564.14</p><p>28.33</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_9000_1</p><p>0.9837</p><p>90.08</p><p>176.96</p><p>0.16%</p><p>7.63</p><p>7.61</p><p>OpenSearch</p><p>100_9000_1</p><p>0.9821</p><p>687.25</p><p>23.25</p><p></p><p></p><p></p><p>Elasticsearch</p><p>100_10000_1</p><p>0.9848</p><p>97.64</p><p>163.31</p><p>0.08%</p><p>8.38</p><p>8.36</p><p>OpenSearch</p><p>100_10000_1</p><p>0.984</p><p>818.64</p><p>19.53</p><p></p><p></p><p></p><p>예를 들어, <code>100_9000_1</code>에서 OpenSearch는 검색당 평균 687밀리초를 기록하는 반면, Elasticsearch에서는 90밀리초이며, 10단계 검색 루프에서는 약 10x(687-90)=6초의 추가 대기 시간이 발생합니다. </p><p><a href="https://github.com/elastic/competitive-benchmarking-studies/tree/main/es-9.3-vs-os-3.5-vector-search/jingra/results/20260220">전체 결과</a> 보기.</p><h3>방법론</h3><p>Python을 사용하여 쿼리를 전송하고 응답 시간 및 기타 통계를 추적하기 위해 다음 쿼리를 각 엔진에 전송했습니다. 벡터 검색 엔진의 성능은 고려할 후보 수, 재채점의 적극성, 반환할 컨텍스트의 양 등 핵심 매개변수를 어떻게 조정하느냐에 따라 달라진다는 점을 유의하시기 바랍니다. 이러한 설정은 재현율(올바른 답변을 찾을 가능성)과 대기 시간(결과를 얻는 속도)에 직접적인 영향을 미칩니다.</p><p>벤치마크 테스트에서는 에이전틱 검색 루프에서 일반적으로 조정하는 것과 동일한 후보, 재채점, 결과 크기 설정을 사용하여 해당 워크로드에서 Elasticsearch의 성능을 측정했습니다. 그런 다음 참조를 위해 동일한 설정으로 OpenSearch를 실행했습니다.</p><p>OpenSearch</p>GET &lt;INDEX_NAME&gt;/_search
{
  "query": {
    "knn": {
      "&lt;DENSE_VECTOR_FIELD_NAME&gt;": {
        "vector": [...],
        "k": &lt;NUMBER_OF_CANDIDATES&gt;,
        "method_parameters": {
          "ef_search": &lt;NUMBER_OF_CANDIDATES&gt;
        },
        "rescore": {
          "oversample_factor": &lt;OVERSAMPLE&gt;
        },
        "filter": {
          &lt;SOME_FILTER&gt;
        }
      }
    }
  },
  "size": &lt;RESULT_SIZE&gt;,
  "_source": {
    "excludes": [
      "&lt;DENSE_VECTOR_FIELD_NAME&gt;"
    ]
  }
}<ul><li><p><code>"size": &lt;RESULT_SIZE&gt;</code>: 클라이언트에 반환된 결과 수입니다. 이 벤치마크에서는 Recall@100을 계산하기 위해 결과 크기가 100입니다.</p></li><li><p><code>"k": &lt;NUMBER_OF_CANDIDATES&gt;</code>: 최근접 이웃 후보의 수입니다.</p></li><li><p><code>"ef_search": &lt;NUMBER_OF_CANDIDATES&gt;</code>: 검사할 벡터의 개수.</p></li><li><p><code>"oversample_factor": &lt;OVERSAMPLE&gt;</code>: 재채점 전에 검색되는 후보 벡터의 수입니다.</p></li></ul><p>Elasticsearch</p>GET &lt;INDEX_NAME&gt;/_search
{
  "query": {
    "knn": {
      "field": "&lt;DENSE_VECTOR_FIELD_NAME&gt;",
      "query_vector": [...],
      "k": &lt;NUMBER_OF_CANDIDATES&gt;,
      "num_candidates": &lt;NUMBER_OF_CANDIDATES&gt;,
      "rescore_vector": {
        "oversample": &lt;OVERSAMPLE&gt;
      },
      "filter": {
        &lt;SOME_FILTER&gt;
      }
    }
  },
  "size": &lt;RESULT_SIZE&gt;,
  "_source": {
    "excludes": [
      "&lt;DENSE_VECTOR_FIELD_NAME&gt;"
    ]
  }
}<ul><li><p><code>"size": &lt;RESULT_SIZE&gt;</code>: 클라이언트에 반환된 결과 수입니다. 이 벤치마크에서는 Recall@100을 계산하기 위해 결과 크기가 100입니다.</p></li><li><p><code>"k": &lt;NUMBER_OF_CANDIDATES&gt;</code>각 샤드에서 반환할 가장 가까운 이웃의 수입니다.</p></li><li><p><code>"num_candidates": &lt;NUMBER_OF_CANDIDATES&gt;</code>: <code>knn</code> 검색 수행 시 샤드별로 고려할 최근접 이웃 후보 수.</p></li><li><p><code>"oversample": &lt;OVERSAMPLE&gt;</code>: 재채점 전에 검색되는 후보 벡터의 수입니다.</p></li></ul><p>예</p><p><code>Knn</code> 쿼리(<code>100_500_1</code>)는 다음과 같습니다.</p><p>OpenSearch</p>GET search_catalog_128/_search
{
  "query": {
    "knn": {
      "search_catalog_embedding": {
        "vector": [...],
        "k": 500,
        "method_parameters": {
          "ef_search": 500
        },
        "rescore": {
          "oversample_factor": 1
        },
        "filter": {
          "term": {
            "valid": true
          }
        }
      }
    }
  },
  "size": 100,
  "_source": {
    "excludes": [
      "search_catalog_embedding"
    ]
  }
}<p>Elasticsearch</p>GET search_catalog_128/_search
{
  "query": {
    "knn": {
      "field": "search_catalog_embedding",
      "query_vector": [...],
      "k": 500,
      "num_candidates": 500,
      "rescore_vector": {
        "oversample": 1
      },
      "filter": {
        "term": {
          "valid": true
        }
      }
    }
  },
  "size": 100,
  "_source": {
    "excludes": [
      "search_catalog_embedding"
    ]
  }
}<p>전체 구성, Terraform 스크립트, Kubernetes 매니페스트 및 벤치마킹 코드는 이 <a href="https://github.com/elastic/competitive-benchmarking-studies">저장소</a>의 <a href="https://github.com/elastic/competitive-benchmarking-studies/tree/main/es-9.3-vs-os-3.5-vector-search">es-9.3-vs-os-3.5-vector-search</a> 폴더에서 확인할 수 있습니다.</p><h3>클러스터 설정</h3><p>테스트는 각각 16개의 vCPU와 64GB RAM을 갖춘 6개의 e2-standard-16 클라우드 서버에서 실행되었습니다. 각 서버에서 검색 엔진 노드를 실행하는 각 Kubernetes 포드에 15개의 vCPU와 56GB RAM을 할당하였으며, 그 중 28GB는 JVM 힙을 위해 예약했습니다.</p><p>클러스터는 Elasticsearch 9.3.0과 OpenSearch 3.5.0 (Lucene 10.3.2)을 실행합니다. 이 벤치마크에서 두 시스템 모두 동일한 Lucene 버전을 사용하기 때문에, 관찰된 처리량과 지연 시간 차이는 Lucene에만 기인하는 것이 아니라 각 엔진이 필터링된 kNN(k-최근 이웃) 검색 및 재채점을 통합하고 실행하는 방식의 차이를 반영합니다. 3개의 기본 샤드와 1개의 복제본이 있는 단일 인덱스를 사용했습니다(따라서 노드당 1개씩 총 6개의 샤드).</p><p>또한 같은 지역 내 별도의 서버를 사용해 벤치마크 클라이언트를 실행하고 타이밍 통계를 수집했습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7c7bdd567395d5b7/6a170bf3c1e8a56ee2f882f6/f81002c9186e4c2d3e92f49d72418fee9860fc5e-761x401.png" alt="Elasticsearch 및 OpenSearch 벤치마크를 위한 클러스터링" /><h3>데이터 세트</h3><p></p><p>이 벤치마크에서는 대규모 실제 환경에서의 필터링된 벡터 검색을 반영하도록 설계된 대규모 이커머스 스타일의 카탈로그 임베딩 데이터 세트(2,000만 개 문서)을 사용했습니다.</p><p></p><p>각 문서는 카탈로그 항목을 나타내며 다음을 포함합니다.</p><p></p><ul><li><p>128차원 고밀도 벡터 임베딩으로, 대략적인 kNN 검색에 사용됩니다.</p></li><li><p>필터링에 사용되는 구조화된 메타데이터 필드(예: 항목 유효성 및 가용성, 기타 카탈로그 제약 조건)는 적합한 하위 집합 내에서만 가장 가까운 이웃을 검색하는 일반적인 제작 패턴을 지원합니다.</p></li></ul><p></p><p>이 데이터 세트를 선택한 이유는 선택한 이유는 프로덕션 환경의 에이전틱 및 RAG 스타일 시스템에서 나타나는 핵심 성능 과제를 잘 반영하기 때문입니다. 벡터 유사도만으로는 충분하지 않고, 검색은 필터에 의해 제한을 받는 경우가 많고, 시스템은 해당 제약 조건 하에서 지연 시간을 낮게 유지하면서 높은 재현율을 달성해야 합니다. 소규모 QA 스타일 데이터 세트와 비교했을 때, 2,000만 개 문서 코퍼스는 실제 환경에서 필터링된 ANN 시스템이 직면하는 규모와 후보 압력을 더 잘 반영합니다.</p><h2>결론</h2><p>현대 AI 아키텍처, 특히 컨텍스트 엔지니어링을 중심으로 구축된 아키텍처에서 벡터 검색 속도는 사소한 구현 세부 사항으로 치부할 수 없습니다. 이는 효과를 배가시킵니다. 에이전트와 워크플로가 검색 → 추론 → 검색 과정을 반복할 때, 검색 성능은 엔드투엔드 지연 시간, 처리량, 모델에 입력되는 컨텍스트 품질에 직접적인 영향을 미칩니다.</p><p>벤치마크 테스트 결과, Elasticsearch는 정확한 문서 검색 여부가 중요한 시나리오(단순히 유사한 벡터를 검색하는 것이 아닌)에서 OpenSearch보다 지속적으로 더 높은 재현율과 더 낮은 지연 시간을 제공했습니다. 제어된 데이터 세트에서 차이는 분명하며, 실제 환경에서는 대규모 검색 호출 전반에 걸쳐 이러한 이점이 누적되어 응답성을 향상시키고, 용량 여유를 확대하며, 인프라 비용을 절감합니다.</p><h3>추가 읽기</h3><ol><li><p><a href="https://www.elastic.co/search-labs/blog/context-engineering-overview">컨텍스트 엔지니어링이란 무엇인가요?</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/series/context-engineering-hybrid-search-evolution">하이브리드 검색 및 컨텍스트 엔지니어링의 발전</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/context-engineering-relevance-ai-agents-elasticsearch">AI 에이전트를 위한 컨텍스트 엔지니어링에서 관련성의 영향</a></p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/opensearch-vs-elasticsearch-filtered-vector-search</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/opensearch-vs-elasticsearch-filtered-vector-search</guid>
    <category><![CDATA[벡터 데이터베이스]]></category>
    <dc:creator><![CDATA[Sachin Frayne]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4b38e5114bbf098c/6a170bf560084b3a6c3c459d/fb7ee623925ca6696d643e437ce8efe5fe749079-1280x720.png" length="0" type="image/png"/>
    <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[더 나은 바이너리 정량화(BBQ)를 사용 사례에 구현하는 방법]]></title>
    <description><![CDATA[사용 사례에서 더 나은 이진 정량화(BBQ)를 구현하는 이유와 그 방법을 살펴보세요.]]></description>
    <content:encoded><![CDATA[<p>벡터 검색은 텍스트에 대한 시맨틱 검색이나 이미지, 동영상 또는 오디오에 대한 유사도 검색을 구현할 때 기초를 제공합니다. 벡터 검색에서 벡터는 방대하고 때로는 느릴 수 있는 데이터를 수학적으로 표현한 것입니다. 더 나은 이진 양자화(이하 BBQ)는 벡터의 압축 방법으로 작동합니다. 벡터를 축소하여 검색 및 처리 속도를 높이면서 적합한 일치 항목을 찾을 수 있습니다. 이 글에서는 벡터를 자동으로 채점하는 정량화된 인덱스에만 사용할 수 있는 필드인 BBQ와 rescore_vector에 대해 설명합니다.</p><p>이 문서에 언급된 모든 전체 쿼리와 출력은 <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/how-and-why-bbq">Elasticsearch Labs 코드 리포지토리에서</a> 확인할 수 있습니다.</p><h2>사용 사례에서 더 나은 이진 정량화(BBQ)를 구현하는 이유는 무엇인가요?</h2>참고: BBQ의 수학적 원리에 대한 자세한 내용은 아래의 <a href="https://www.elastic.co/kr/search-labs/blog/bbq-implementation-into-use-case#further-learning">'추가 학습' 섹션을</a> 참조하세요. 이 블로그에서는 구현에 초점을 맞추고 있습니다.<p>수학은 흥미롭지만, 벡터 검색의 정확성을 유지하려면 그 이유를 완전히 파악하는 것이 중요합니다. 현재의 벡터 검색 알고리즘으로는 데이터 읽기 속도에 제한이 있다는 것이 밝혀졌기 때문에 궁극적으로 이것은 압축에 관한 것입니다. 따라서 해당 데이터를 모두 메모리에 넣을 수 있다면 스토리지에서 읽을 때보다 속도가 크게 향상됩니다<a href="https://sre.google/static/pdf/rule-of-thumb-latency-numbers-letter.pdf">(메모리는 SSD보다 약 200배 빠릅니다</a>).</p><p>몇 가지 유의해야 할 사항이 있습니다:</p><ul><li><p><a href="https://arxiv.org/pdf/1603.09320">HNSW</a> (계층 탐색 가능한 작은 세계)와 같은 그래프 기반 인덱스는 벡터 검색에 가장 빠릅니다.</p><ul><li><p>HNSW: 다층 그래프 구조를 구축하여 효율적인 고차원 유사도 검색을 가능하게 하는 근사 근사 이웃 검색 알고리즘입니다.</p></li></ul></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt760bd95c206bfa8f/6a17e2ad505ac393f7ad8a95/590f3b3c72a76023a38a0436cd9ff90a9f80e936-1964x1262.png" alt="HNSW: 다층 그래프 구조를 구축하여 효율적인 고차원 유사도 검색을 가능하게 하는 근사 근사 이웃 검색 알고리즘입니다." /><ul><li><p>HNSW는 메모리 또는 최악의 경우 스토리지에서 데이터를 읽는 속도에 의해 근본적으로 속도가 제한됩니다.</p><ul><li><p>이상적으로는 저장된 모든 벡터를 메모리에 로드할 수 있어야 합니다.</p></li></ul></li><li><p>임베딩 모델은 일반적으로 부동 소수점 숫자당 4바이트의 플로트32 정밀도를 가진 벡터를 생성합니다.</p></li><li><p>마지막으로, 보유하고 있는 벡터 및/또는 치수의 수에 따라 모든 벡터를 저장하기 위한 메모리가 매우 빠르게 부족해질 수 있습니다.</p></li></ul><p>이를 당연하게 생각하면, 수백 또는 수천 개의 차원을 가진 수백만 또는 수십억 개의 벡터를 수집하기 시작하면 문제가 빠르게 발생한다는 것을 알 수 있습니다. '<a href="https://www.elastic.co/kr/search-labs/blog/bbq-implementation-into-use-case#approximate-numbers-on-the-compression-ratios">압축률에 대한 대략적인</a>수치'라는 제목의 섹션에서 대략적인 수치를 확인할 수 있습니다.</p><h2>시작하려면 무엇이 필요하나요?</h2><p>시작하려면 다음이 필요합니다:</p><ul><li><p>Elastic Cloud 또는 온프레미스를 사용하는 경우, 8.18 이상의 Elasticsearch 버전이 필요합니다. BBQ는 8.16에 도입되었지만, 이 글에서는 8.18에 도입된 <code>vector_rescore</code> 을 사용합니다.</p></li><li><p>또한 클러스터에 <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/ml-settings.html">머신 러닝(ML) 노드가</a> 있는지 확인해야 합니다. (참고: 모델을 로드하려면 최소 4GB의 ML 노드가 필요하지만 전체 프로덕션 워크로드에는 훨씬 더 큰 노드가 필요할 수 있습니다.)</p></li><li><p>서버리스를 사용하는 경우 벡터에 최적화된 인스턴스를 선택해야 합니다.</p></li><li><p>또한 벡터 데이터베이스에 대한 기본 지식이 필요합니다. Elastic의 벡터 검색 개념에 아직 익숙하지 않으시다면 먼저 다음 리소스를 확인해보시는 것이 좋습니다:</p><ul><li><p><a href="https://www.elastic.co/kr/search-labs/blog/elastic-vector-database-practical-example">Elastic Vector 데이터베이스 탐색</a></p></li><li><p><a href="https://www.elastic.co/kr/blog/retrieval-augmented-generation-explained">검색 증강 생성의 핵심 아이디어</a></p></li></ul></li></ul><h2>더 나은 바이너리 정량화(BBQ) 구현</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt18df00df95ff2ca7/6a17e2af414c6411989450df/4d388078495566f0527e931e0c2e38facdce83c6-1503x748.png" alt="Elasticsearch bbq 구현." /><p>이 블로그는 간결하게 유지하기 위해 기본 제공 기능을 사용할 수 있는 경우 이를 사용합니다. 이 경우, 머신 러닝 노드에서 Elasticsearch 내부에서 직접 실행되는 <a href="https://www.elastic.co/kr/guide/en/machine-learning/8.17/ml-nlp-e5.html"><code>.multilingual-e5-small</code></a> 벡터 임베딩 모델이 있습니다. <code>text_embedding</code> 모델을 원하는 임베더<a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/infer-service-openai.html">(OpenAI</a>, <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/infer-service-google-ai-studio.html">Google AI Studio</a>, <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/infer-service-cohere.html">Cohere</a> 등)로 대체할 수 있습니다. 선호하는 모델이 아직 통합되지 않은 경우, <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/bring-your-own-vectors.html">자체 고밀도 벡터 임베딩을 가져올</a> 수도 있습니다.)</p><p>먼저, 주어진 텍스트에 대한 벡터를 생성하기 위해 추론 엔드포인트를 만들어야 합니다. 이 모든 명령은 Kibana <a href="https://www.elastic.co/kr/guide/en/kibana/8.18/console-kibana.html">개발자 도구 콘솔에서</a> 실행합니다. 이 명령은 <code>.multilingual-e5-small</code> 을 다운로드합니다. 아직 존재하지 않으면 엔드포인트가 설정되며, 실행하는 데 1분 정도 걸릴 수 있습니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/01-create-an-inference-endpoint-output.json">01-create-an-inference-endpoint-output.json</a> 파일에서 확인할 수 있습니다. </p>PUT _inference/text_embedding/my_e5_model
{
  "service": "elasticsearch",
  "service_settings": {
    "num_threads": 1,
    "model_id": ".multilingual-e5-small",
    "adaptive_allocations": {
      "enabled": true,
      "min_number_of_allocations": 1
    }
  }
}<p>반환되면 모델이 설정되고 다음 명령을 사용하여 모델이 예상대로 작동하는지 테스트할 수 있습니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/02-embed-text-output.json">02-embed-text-output.json</a> 파일에서 확인할 수 있습니다.</p>POST _inference/text_embedding/my_e5_model
{
  "input": "my awesome piece of text"
}<p>학습된 모델이 노드에 할당되지 않는 문제가 발생하면 모델을 수동으로 시작해야 할 수 있습니다.</p>POST _ml/trained_models/.multilingual-e5-small/deployment/_start<p>이제 임베딩 모델의 출력과 일치하도록 표준 텍스트 필드(<code>my_field</code>)와 384개의 차원을 가진 고밀도 벡터 필드(<code>my_vector</code>)의 두 가지 속성을 가진 새 매핑을 만들어 보겠습니다. 또한 <code>index_options.type to bbq_hnsw</code> 을 재정의합니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/03-create-byte-qauntized-index-output.json">03-create-byte-qauntized-index-output.json</a> 파일에서 확인할 수 있습니다.</p>PUT bbq-my-byte-quantized-index
{
  "mappings": {
    "properties": {
      "my_field": {
        "type": "text"
      },
      "my_vector": {
        "type": "dense_vector",
        "dims": 384,
        "index_options": {
          "type": "bbq_hnsw"
        }
      }
    }
  }
}<p>Elasticsearch가 벡터를 생성하도록 하기 위해 <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/ingest.html">수집 파이프라인을</a> 사용할 수 있습니다. 이 파이프라인에는 엔드포인트(<code>model_id</code>), 벡터를 생성하려는 <code>input_field</code>, 벡터를 저장할 <code>output_field</code>, 이 세 가지가 필요합니다. 아래의 첫 번째 명령은 추론 <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/current/inference-apis.html">서비스를 </a>내부적으로 사용하는 추론 수집 파이프라인을 만들고, 두 번째 명령은 파이프라인이 올바르게 작동하는지 테스트합니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/04-create-and-simulate-ingest-pipeline-output.json">04-create-and-simulate-ingest-pipeline-output.json</a> 파일에서 확인할 수 있습니다. </p>PUT _ingest/pipeline/my_inference_pipeline
{
  "processors": [
    {
      "inference": {
        "model_id": "my_e5_model",
        "input_output": [
          {
            "input_field": "my_field",
            "output_field": "my_vector"
          }
        ]
      }
    }
  ]
}

POST _ingest/pipeline/my_inference_pipeline/_simulate
{
  "docs": [
    {
      "_source": {
        "my_field": "my awesome text field"
      }
    }
  ]
}<p>이제 아래의 처음 두 명령어로 문서를 추가하고 세 번째 명령어로 검색이 제대로 작동하는지 테스트할 준비가 되었습니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/05-bbq-index-output.json">05-bbq-index-output.json</a> 파일에서 확인할 수 있습니다. </p>PUT bbq-my-byte-quantized-index/_doc/1?pipeline=my_inference_pipeline
{
    "my_field": "my awesome text field"
}

PUT bbq-my-byte-quantized-index/_doc/2?pipeline=my_inference_pipeline
{
    "my_field": "some other sentence"
}

GET bbq-my-byte-quantized-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "knn": {
            "field": "my_vector",
            "query_vector_builder": {
              "text_embedding": {
                "model_id": "my_e5_model",
                "model_text": "my awesome search field"
              }
            },
            "k": 10,
            "num_candidates": 100
          }
        }
      ]
    }
  },
  "_source": [
    "my_field"
  ]
}<p><a href="https://www.elastic.co/kr/search-labs/blog/better-binary-quantization-lucene-elasticsearch#lucene-benchmarking">이 게시물에서</a> 권장하는 바와 같이, 리스코어링과 오버샘플링은 압축의 이점을 활용하면서 높은 리콜 정확도를 유지하는 데 도움이 되므로 데이터 양이 많지 않은 경우 확장하는 것이 좋습니다. Elasticsearch 버전 8.18부터는 <a href="https://www.elastic.co/kr/guide/en/elasticsearch/reference/8.18/knn-search.html#dense-vector-knn-search-rescoring">rescore_vector를</a> 사용하여 이 작업을 수행할 수 있습니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/06-bbq-search-8-18-output.json">06-bbq-search-8-18-output.json</a> 파일에 있습니다.</p>GET bbq-my-byte-quantized-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "knn": {
            "field": "my_vector",
            "query_vector_builder": {
              "text_embedding": {
                "model_id": "my_e5_model",
                "model_text": "my awesome search field"
              }
            },
            "rescore_vector": {
              "oversample": 3
            },
            "k": 10,
            "num_candidates": 100
          }
        }
      ]
    }
  },
  "_source": [
    "my_field"
  ]
}<p>이 점수는 원시 데이터에 대해 얻을 수 있는 점수와 어떻게 비교될까요? 위의 모든 작업을 다시 수행하되 <code>index_options.type: hnsw</code> 을 사용하면 점수가 매우 비슷하다는 것을 알 수 있습니다. 예상 출력은 출력 폴더의 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/how-and-why-bbq/Outputs/07-raw-vector-output.json">07-raw-vector-output.json</a> 파일에서 확인할 수 있습니다.</p>PUT my-raw-vector-index
{
  "mappings": {
    "properties": {
      "my_field": {
        "type": "text"
      },
      "my_vector": {
        "type": "dense_vector",
        "dims": 384,
        "index_options": {
          "type": "hnsw"
        }
      }
    }
  }
}

PUT my-raw-vector-index/_doc/1?pipeline=my_inference_pipeline
{
    "my_field": "my awesome text field"
}

PUT my-raw-vector-index/_doc/2?pipeline=my_inference_pipeline
{
    "my_field": "some other sentence"
}

GET my-raw-vector-index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "knn": {
            "field": "my_vector",
            "query_vector_builder": {
              "text_embedding": {
                "model_id": "my_e5_model",
                "model_text": "my awesome search field"
              }
            },
            "k": 10,
            "num_candidates": 100
          }
        }
      ]
    }
  },
  "_source": [
    "my_field"
  ]
}<h2>압축률에 대한 대략적인 수치</h2><p>벡터 검색으로 작업할 때 저장 공간과 메모리 요구 사항은 금방 큰 문제가 될 수 있습니다. 다음 분석은 다양한 양자화 기법이 벡터 데이터의 메모리 사용량을 어떻게 획기적으로 줄이는지 보여줍니다.</p><p>벡터(V)</p><p>치수(D)</p><p>원시(V x D x 4)</p><p>int8 (V x (D x 1 + 4))</p><p>int4 (V x (D x 0.5 + 4))</p><p>bbq (V x (D x 0.125 + 4))</p><p>10,000,000</p><p>384</p><p>14.31GB</p><p>3.61GB</p><p>1.83GB</p><p>0.58GB</p><p>50,000,000</p><p>384</p><p>71.53GB</p><p>18.07GB</p><p>9.13GB</p><p>2.89GB</p><p>100,000,000</p><p>384</p><p>143.05GB</p><p>36.14GB</p><p>18.25GB</p><p>5.77GB</p><h2>결론</h2><p>BBQ는 정확도 저하 없이 압축을 위해 벡터 데이터에 적용할 수 있는 최적화 기능입니다. 벡터를 비트로 변환하여 데이터를 효과적으로 검색하고 AI 워크플로우를 확장하여 검색을 가속화하고 데이터 저장 공간을 최적화할 수 있도록 지원합니다.</p><h2>추가 학습</h2><p>BBQ에 대해 더 자세히 알고 싶다면 다음 리소스를 확인하세요:</p><ul><li><p><a href="https://www.elastic.co/kr/search-labs/blog/better-binary-quantization-lucene-elasticsearch">루씬과 Elasticsearch의 이진 정량화(BBQ)</a></p></li><li><p><a href="https://www.elastic.co/kr/search-labs/blog/bit-vectors-elasticsearch-bbq-vs-pq">더 나은 바이너리 정량화(BBQ) 대 제품 정량화</a></p></li><li><p><a href="https://www.elastic.co/kr/search-labs/blog/optimized-scalar-quantization-elasticsearch">최적화된 스칼라 양자화: 더욱 향상된 바이너리 양자화</a></p></li><li><p><a href="https://www.youtube.com/watch?v=04NzMt2Nigc">더 나은 바이너리 정량화(BBQ): 바이트에서 BBQ로, 더 나은 벡터 검색의 비결, 벤 트렌트의 글</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/bbq-implementation-into-use-case</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/bbq-implementation-into-use-case</guid>
    <category><![CDATA[벡터 데이터베이스]]></category>
    <category><![CDATA[기본]]></category>
    <dc:creator><![CDATA[Sachin Frayne,Jessica Garson]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3dd0495b536b2615/6a17e2b0414c6488459450e3/66842055367cdd795532b01c167f2a4b03dc65e3-1200x628.png" length="0" type="image/png"/>
    <pubDate>Wed, 23 Apr 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>