<?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[Elastic 내부 - 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[Elastic 내부 - 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/blog/category/inside-elastic</link>
    </image>
    <link>https://www.elastic.co/kr/search-labs/blog/category/inside-elastic</link>
    <atom:link href="https://www.elastic.co/kr/search-labs/rss/category/inside-elastic.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[kr]]></language>
    <lastBuildDate>Tue, 29 Sep 2026 09:34:12 GMT</lastBuildDate>
  <item>
    <title><![CDATA[세계에서 가장 빠른 벡터 검색을 위해 Elasticsearch simdvec을 구축한 방법]]></title>
    <description><![CDATA[Elasticsearch의 모든 벡터 검색 쿼리 뒤에 있는 수동 조정 SIMD 커널 라이브러리인 Elasticsearch simdvec을 어떻게 구축했는지 알아보세요.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch simdvec은 Elasticsearch의 모든 벡터 거리 계산의 기반이 되는 엔진입니다. Elasticsearch가 지원하는 모든 벡터 유형에 대해 수동 조정 AVX-512 및 NEON 커널을 제공합니다. 벌크 스코어링 아키텍처는 x86에서는 명시적 프리페칭을 통해, ARM에서는 인터리브 로딩을 통해 메모리 지연 시간을 숨기며 데이터가 CPU 캐시를 초과할 때 FAISS 및 jvector와 같은 라이브러리보다 최대 4배까지 성능이 향상됩니다. 이 글에서는 simdvec을 구축한 이유와 내부 구성 요소, 그리고 이 라이브러리가 어떻게 Elasticsearch 벡터 검색을 세계에서 가장 빠른 검색으로 만드는지 설명합니다.</p><h2>Elasticsearch simdvec을 어떻게 구축했는지</h2><p>Elasticsearch의 모든 벡터 검색 쿼리는 <a href="https://arxiv.org/abs/1603.09320">Hierarchical Navigable Small World(HNSW)</a> 순회, 역파일(IVF) 스캔, 순위 재지정 단계 등 어떤 방식이든 동일한 문제, 즉 쿼리당 수백만 번씩 벡터 간의 거리를 계산하는 작업으로 귀결됩니다. Elasticsearch는 float32, int8, bfloat16, 바이너리, 그리고 Better Binary Quantization(BBQ) 등 다양한 데이터 유형과 양자화 전략을 지원합니다. 각 전략은 메모리, 처리량, 재현율 측면에서 서로 다른 장단점이 있습니다. 이 모든 것을 가능하게 하는 것은 바로 simdvec이라는 단일 엔진입니다.</p><p>하드웨어 성능을 최대한 활용하여 모든 거리 계산을 빠르게 수행하기 위해 simdvec을 개발했습니다. 이 글에서는 simdvec을 구축한 이유, 내부 구성 요소, 그리고 가장 큰 효과를 발휘하는 부분에 대해 설명합니다.</p><h3>레이싱카처럼 구축</h3><p>Formula 1 애호가들로서, 그리고 이중 한 명이 이전에 Ferrari Formula 1 팀에서 근무했던 경험을 바탕으로, 저희는 분명한 공통ㄴ점을 발견했습니다. Formula 1 자동차는 단 하나의 목적, 즉 최고의 랩 타임을 달성하는 것을 위해 설계됩니다. 엔진 출력, 공기역학, 섀시 설계는 오직 그 결과에 기여하는 한에서만 중요합니다. 벡터 데이터베이스도 마찬가지로, 인덱싱 처리량, 쿼리 지연 시간, 그리고 재현율이 성공을 좌우합니다.</p><p>최종 결과가 중요하지만, 최고 수준의 성능을 달성하려면 각 구성 요소가 최상의 성능을 발휘해야 합니다. 단순히 <em>충분히 좋은</em> 정도가 아니라, 해당 범주에서 <em>최고</em>여야 합니다. simdvec은 이러한 사고방식을 바탕으로 시스템의 핵심 요소인 엔진에 집중하여 개발되었습니다. <a href="https://en.wikipedia.org/wiki/Single_instruction,_multiple_data">단일 명령어 다중 데이터</a>(SIMD)에 최적화된 특수 목적 커널 라이브러리로, Java에서 <a href="https://openjdk.org/projects/panama/">Panama</a> F외부 함수 인터페이스(FFI)를 통해 호출되는 수동 조정 네이티브 C++ 거리 함수를 제공합니다. 벌크 스코어링, 캐시 라인 프리페칭, 그리고 Elasticsearch에서 사용되는 모든 벡터 유형 및 레이아웃을 지원합니다.</p><p>모든 쿼리 뒤에 있는 엔진입니다.</p><h3>왜 저희가 직접 구축했는지</h3><p>2023년에 Apache Lucene의 Panama Vector API로 시작했습니다. float32 내적에는 잘 작동했지만, Elasticsearch의 요구 사항은 빠르게 충족할 수 있는 범위를 넘어섰습니다. Elasticsearch는 int8, int4, bfloat16, 단일 비트, 비대칭 BBQ 등 다양한 양자화 벡터 유형을 지원합니다. 각 유형은 서로 다른 SIMD 전략, 패킹 레이아웃, 누산기 요구 사항을 가지고 있습니다. 유형 지원 외에도 Elasticsearch의 스코어링 경로는 단일 쌍 처리량 이상의 것을 요구합니다. HNSW는 한 번의 단계로 여러 그래프 이웃을 스코어링해야 하고, IVF는 프리페칭을 통해 수천 개의 후보를 벌크 스코어링해야 하며, 디스크 기반 스코어링은 복사 없이 mmap된 메모리에서 직접 작동해야 합니다. 사용 가능한 기존 라이브러리를 살펴보았지만, 모든 요구 사항을 충족하는 것은 없었습니다.</p><p>그래서 simdvec을 구축했습니다. simdvec은 FFI를 통해 Java에서 호출되는 수동 조정 네이티브 C++ 커널로, 벌크 스코어링, 프리페칭, 그리고 Elasticsearch에서 사용하는 모든 벡터 유형을 지원합니다. 라이브러리를 직접 소유함으로써 전체 스택을 제어할 수 있습니다. BBQ와 같은 새로운 양자화 유형을 추가하면 시스템 전체에 걸쳐 최적화된 SIMD 커널이 연결됩니다. 상위 라이브러리의 지원을 기다리지 않으며, 어떤 유형에 대해서도 성능이 저하되지 않습니다. Elasticsearch의 모든 벡터 쿼리(HNSW, IVF, 순위 재지정 또는 하이브리드)는 실제로 사용하는 연산 및 유형을 중심으로 구축된 이 엔진에서 실행됩니다.</p><p>simdvec은 x86 및 ARM용으로 별도의 네이티브 라이브러리를 제공하며, 각 라이브러리는 시작 시 여러 명령어 세트 아키텍처(ISA) 계층을 선택할 수 있습니다. FFI를 통한 Java의 호출 오버헤드는 <a href="https://github.com/ldematte/simsimd-benchmarks/blob/main/COMPARISON.md#ffm-downcall-overhead-measurements">한 자릿수 나노초</a>로 매우 낮습니다.</p><h3>환경</h3><p>SIMD 최적화 벡터 거리 커널을 개발하는 곳은 저희뿐만이 아닙니다. 생태계는 매우 풍부하며, 저희는 simdvec의 성능을 이해하고 싶었습니다. 프로젝트 순위를 매기려는 것이 아니라 컨텍스트를 제공하고 Elasticsearch 엔진의 위치를 설명하기 위해서입니다. 각기 다른 접근 방식을 대표하는 세 가지 프로젝트를 참조 대상으로 선정했습니다.</p><ul><li><p><strong>jvector:</strong> x86에서 네이티브 C 가속 옵션과 함께 벡터화된 거리 계산을 위해 Panama Vector API를 사용하는 Java 근사 최근접 이웃(ANN) 라이브러리입니다.</p></li><li><p><strong>FAISS:</strong> 널리 배포된 오픈 소스 벡터 검색 프레임워크로, 수동 조정 AVX2/AVX-512 커널을 사용합니다.</p></li><li><p><strong>NumKong</strong> (이전 SimSIMD): 거리 함수, 행렬 연산 및 지리 공간 계산을 아우르는 2,000개 이상의 수동 조정 SIMD 커널로 구성된 종합적인 제품군입니다.</p></li></ul><p>각 프로젝트는 서로 다른 목적을 가지고 있으며 각기 다른 절충점을 고려합니다. Elasticsearch에서 필요한 특정 연산에 대한 simdvec의 성능을 이해하는 데 도움이 되도록 각 프로젝트의 참조 번호를 제공합니다.</p><h3>측정 방법</h3><p>simdvec 및 <a href="https://github.com/ChrisHegarty/jvector-kernel-benchmarks">jvector 벤치마크</a>는 표준 JVM 마이크로벤치마크 도구인 JMH를 사용하여 Java로 작성되었으며, FFI 오버헤드가 포함되어 있습니다. <a href="https://github.com/ldematte/simsimd-benchmarks">NumKong 벤치마크</a>와 <a href="https://github.com/ChrisHegarty/faiss-kernel-benchmarks">FAISS 벤치마크</a>의 경우, 표준 C++ 마이크로벤치마크 프레임워크인 Google Benchmark를 사용하여 소규모 C/C++ 하네스를 작성했습니다. 두 프레임워크 모두 웜업 및 반복 보정을 거쳐 연산당 나노초 단위의 시간을 보고합니다. 하드웨어 성능 카운터를 통해 모든 라이브러리가 두 플랫폼 모두에서 SIMD를 사용하고 있음을 확인했습니다. 모든 벤치마크 코드는 링크된 GitHub 리포지토리(그리고 simdvec의 경우 <a href="https://github.com/elastic/elasticsearch">elasticsearch</a> 리포지토리)에서 공개적으로 사용할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt90a7d66553be3c9d/6a1701d166c4f942caf8bea5/aee116772df161cf86b7668f575ac34c733a23c5-1580x238.png" alt="두 가지 플랫폼을 나열한 표: x86(AMD EPYC Turin(Zen 5), AVX2 및 AVX-512, AWS c8a.4xlarge) 및 ARM(Graviton 4(Neoverse V2), NEON 및 SVE2, AWS c8g.4xlarge)." /><p><strong>소프트웨어:</strong> JDK 25.0.2, JMH 1.37, GCC 14, Google Benchmark(최신).</p><h2>한 번에 하나의 벡터</h2><p>벡터 검색에서 가장 기본적인 연산은 두 벡터 사이의 거리를 계산하는 것입니다. 모든 HNSW 이웃 평가, 모든 IVF 후보 점수, 모든 순위 재지정 비교는 이 내부 루프로 축소됩니다.</p><p>두 플랫폼 모두에서 1024 차원의 단일 쌍 처리량을 측정했으며, 기준 유형이자 생태계 경쟁이 가장 치열한 float32부터 시작했습니다. simdvec을 FAISS 및 jvector와 비교했습니다. NumKong은 float32에 float64 누산기를 사용하기 때문에 (플랫폼에 따라) 처리량보다 수치 정밀도를 우선시하여 3.2배에서 5.3배 느리므로 비교 대상에서 제외했습니다. 공정한 비교를 위해 NumKong은 simdvec과 동일한 누산기 전략을 사용하는 int8에서 벤치마킹했습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte3bc2ecaf3ad2b61/6a1701d2ab7f08039ddb9d0f/352cfa0fc18f123140f746d843404f80127fb1b7-1500x675.png" alt="'float32 Dot Product — AMD Turin'이라는 제목의 가로 막대 차트는 FAISS AVX‑512(23.2ns/op), ES simdvec AVX‑512(28.3ns/op), FAISS AVX2(36.4ns/op), ES simdvec AVX2(38.9ns/op), jvector(43.9ns/op)의 다섯 가지 구현을 비교합니다." /><p>x86에서 FAISS AVX-512는 23ns로 가장 빠른 단일 쌍 커널입니다. simdvec AVX-512는 28ns로 그 뒤를 잇는데, 이 차이는 FFI 호출 오버헤드를 반영합니다. 두 구현 모두 멀티 누산기 언롤링을 사용하는 512비트 FMA를 사용합니다. AVX2 수준에서는 두 구현의 속도가 각각 36ns와 39ns로 훨씬 더 근접하며, 두 구현 모두 256비트 레지스터 및 메모리 로드 폭의 제약을 받습니다. jvector는 Java Panama Vector API를 사용하여 44ns의 성능을 보였습니다. Panama는 우수한 SIMD 코드를 생성하지만, 수동 조정 C++ 내장 함수가 여전히 우위를 점하고 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcbbbe442631a575d/6a1701d42b835f81bcf4b083/95e44d9767f21ec4bccaed835e3c99aa180431ee-1500x495.png" alt="'float32 Dot Produc — Graviton 4(ARM)'이라는 제목의 가로 막대 그래프는 ES simdvec이 70.2ns/op, jvector가 110.0ns/op, FAISS가 155.6ns/op임을 보여줍니다." /><p>ARM에서는 simdvec은 70ns로 jvector(110ns)와 FAISS(156ns)를 크게 앞서고 있습니다. simdvec은 aarch64용으로 수동 조정 NEON 커널을 사용합니다. jvector는 네이티브 ARM 코드가 없으며 Panama에 의존합니다. FAISS는 명시적인 NEON 내장 함수 대신 컴파일러의 자동 벡터화에 의존하기 때문에 성능 차이가 더 큽니다. 이는 커널 라이브러리를 소유함으로써 얻을 수 있는 실질적인 이점을 반영합니다. Elasticsearch가 Graviton으로 확장되었을 때, NEON 전용 커널을 추가했습니다. jvector나 FAISS는 ARM 네이티브 코드에 이처럼 우선순위를 두지 않았습니다.</p><p>하지만 Elasticsearch는 float32만 지원하는 것이 아닙니다. <strong>Int8</strong> 양자화는 메모리 사용량을 4배, bfloat16은 2배, BBQ는 32배 줄여줍니다. 각 유형에는 고유한 SIMD 전략이 필요하며, simdvec은 모든 유형에 대해 수동 조정 네이티브 커널을 제공합니다.</p><p>비교한 라이브러리 중 int8에 대해 유사한 커널을 제공하는 것은 NumKong뿐입니다. 1024 차원에서 int8 내적, 제곱 유클리드, 코사인을 측정했습니다.</p><p><strong>Int8 단일 쌍 스코어링(1,024차원, ns/vec op ― 낮을수록 좋음)</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3ac255d158e93504/6a1701d5a292997e48d00eb1/a0b852fd5f51d57bd2488886600472ee65ab64da-1594x378.png" alt="내적, 제곱 유클리드, 코사인 연산에 대한 x86과 ARM 성능을 비교한 표로, 두 아키텍처에서 각 연산에 대한 ES, NumKong, 차이값이 나열되어 있습니다." /><p>두 아키텍처 모두에서 NumKong은 중소 차원까지는 동일하거나 더 빠르며, 그 차이는 주로 호출 오버헤드(직접 C 호출 vs. Java FFI)가 더 낮기 때문입니다. 더 큰 크기에서는 simdvec이 따라잡는데, 이는 더 효율적인 커널 구현(캐스케이드 언롤링 사용)이 호출 비용을 분산시키기 때문입니다. 차원이 증가함에 따라 <a href="https://github.com/ldematte/simsimd-benchmarks/blob/main/COMPARISON.md#single-pair-i8-nsop-2">이 격차는 줄어들고 결국 역전됩니다</a>. 교차점은 함수와 아키텍처에 따라 768에서 1536 사이의 차원에서 발생합니다.</p><p>Java FFI의 오버헤드가 약간 더 높지만, simdvec은 고도로 최적화된 C/C++ 라이브러리와 동등한 수준입니다. float32 <em>및</em> int8 모두에 대해 최적화된 커널을 제공하는 유일한 라이브러리일 뿐만 아니라, ARM에서는 가장 우수한 성능을 보이며 x86에서는 FAISS에 비해 약간 뒤처지고(float32의 경우), int8의 경우 두 아키텍처 모두에서 NumKong과 매우 유사한 성능을 보입니다. bfloat16, int4, 바이너리, BBQ의 경우에도 대안이 존재하지만, simdvec은 각 유형의 데이터 레이아웃에 맞춰 수동 조정 SIMD를 통해 차별화된 성능을 제공합니다.</p><p>하지만 프로덕션 검색 엔진은 한 번에 하나의 벡터를 점수화하는 것이 아니라 쿼리당 수천 개의 벡터를 점수화합니다. 이제 관건은 이러한 규모에서 실제로 어떤 일이 벌어지는가 하는 점입니다.</p><h3>한 번에 수천 개씩</h3><p>단일 쌍 성능은 전체 그림의 일부일 뿐입니다. 실제로 중요한 것은 시스템이 부하 상태에서 어떻게 작동하는지입니다. 단일 HNSW 쿼리는 수백 개의 그래프 이웃에 점수를 매길 수 있습니다. IVF 스캔은 수천 개의 게시 목록 항목에 점수를 매길 수 있습니다. 순위 재지정 단계는 수만 개의 후보에 점수를 매길 수 있습니다. 단일 쌍 처리량도 중요하지만, 더 중요한 것은 많은 벡터를 얼마나 빨리 점수화할 수 있는지, 그리고 작업 세트가 CPU 캐시 범위를 벗어날 때 성능이 얼마나 완만하게 떨어지는지입니다.</p><p>simdvec은 모든 데이터 유형에 대해 벌크 스코어링을 제공합니다. 이는 단순히 단일 쌍 커널에 대한 루프가 아니라 차원 스트라이드당 한 번씩 쿼리 벡터를 로드하고 여러 문서 벡터에 걸쳐 공유하는 다중 누적기 내부 루프를 사용하며, 다음 배치에 대한 명시적인 캐시 라인 프리페칭을 제공합니다. jvector와 FAISS는 (작성 시점 기준으로) 이와 동등한 기능을 제공하지 않습니다. jvector는 벌크 API가 없으므로 호출자는 루프에서 한 번에 한 쌍씩 점수를 매깁니다. FAISS는 <code>fvec_inner_products_ny</code>을(를) 노출하는데, 작성 시점 기준으로 이는 쿼리 상각이나 프리페칭 없이 단일 쌍 거리 함수에 대한 루프로 구현되어 있습니다.</p><p><strong>Float32.</strong> 커널 수준에서의 영향을 측정하기 위해, HNSW와 유사한 산포 그래프 이웃 조회를 시뮬레이션하는 무작위 접근 패턴을 사용하여 1024 차원 float32 문서 벡터의 개수를 늘려가며 단일 쿼리에 대한 점수를 매겼습니다. 세 가지 데이터 세트 크기(32, 625, 32,500개 벡터)는 작업 세트가 각각 L1, L2, L3 캐시를 초과합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2df64ec77a1921ae/6a1701d714b270393ae3c4de/1d90267be1c63ac82b8ba588617ebedb0be0d1b6-1334x558.png" alt="AMD Turin(x86, AVX‑512) 및 Graviton 4(ARM, NEON)에서 세 가지 크기(32개, 625개, 32,500개 벡터)에 대해 Elasticsearch simdvec, FAISS 및 jvector의 벌크 Float32 내적 스코어링 시간을 비교하는 두 개의 막대 그래프입니다." /><p>데이터가 캐시에 모두 수용될 때, simdvec이 두 플랫폼 모두에서 가장 빠르지만, 커널 산술이 우세하기 때문에 차이는 크지 않습니다. 실제 성능 차이는 작업 세트가 L3를 넘어 커질수록 나타납니다. x86에서 simdvec은 벡터당 95ns를 기록하는 반면, FAISS는 165ns, jvector는 412ns가 필요합니다. ARM에서도 패턴은 동일합니다. simdvec은 162ns를 유지하는 반면, FAISS는 347ns, jvector는 476ns까지 증가합니다. simdvec의 프리페칭 및 쿼리 상각은 단일 쌍 커널에 대한 단순 루프로는 따라잡을 수 없는 방식으로 메모리 지연 시간을 숨겨주며, 이러한 이점은 실제 검색 워크로드가 작동하는 메인 메모리 깊숙한 곳에서 더욱 두드러집니다.</p><p><strong>Int8.</strong> 양자화된 유형에서도 동일한 패턴이 나타납니다. 동일한 L1, L2 및 L3 캐시 경계를 초과하도록 선택된 데이터 세트 크기로 1024 차원에서 int8 내적 벌크 스코어링을 측정하여 루프 내에서 simdvec의 벌크 스코어링과 NumKong의 단일 쌍 스코어링을 비교했습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcda85e10007188d0/6a1701d9cf4f25d722b2cff7/9ee97d98b40d13b19370b76b33e67ea66bfb3250-1580x338.png" alt=" 'x86 — 벌크 스코어링, int8 내적(ns/op, 값이 낮을수록 좋음)'이라는 제목의 표는 세 가지 벡터 크기(128, 2,500, 130,000)에 걸쳐 ES simdvec과 NumKong을 비교하고, 해당 ns/op 값과 속도 향상 비율을 보여줍니다." /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt972c311b7d08ba73/6a1701dadc55dec02ee00c87/601f50a03fa3e6263cbac9700281dfe3e511de60-1580x338.png" alt="'ARM — 벌크 스코어링, int8 내적(ns/op, 값이 낮을수록 좋음)'이라는 제목의 표는 세 가지 벡터 크기(128, 2,500, 130,000)에 걸쳐 ES simdvec과 NumKong을 비교하고, 해당 ns/op 값과 속도 향상 비율을 보여줍니다." /><p>x86에서는 명시적 프리페칭과 배치 처리의 조합으로 simdvec이 1.2배~1.9배 더 빠릅니다. ARM에서도 simdvec은 모든 데이터 세트 크기에서 1.7~1.9배 더 빠른 성능을 보입니다. 이러한 이점은 한 번에 네 개의 벡터를 배치 처리하여 인터리브 액세스 패턴을 통해 메모리 수준의 병렬 처리를 제공하는 데서 비롯됩니다. 두 경우 모두 가장 두드러진 결과는 가장 중요하고 가장 데이터 세트 크기에서 나타납니다.</p><p>제곱 거리 및 코사인에 대한 결과도 유사한 패턴을 보이며, ARM의 경우 1.4~1.8배, x86의 경우 1.3~3.0배의 속도 향상을 보입니다(자세한 내용은 <a href="https://github.com/ldematte/simsimd-benchmarks/blob/main/COMPARISON.md">여기</a>를 참조).</p><h3>메모리가 중요한 경우</h3><p>프로덕션 벡터 인덱스는 일반적으로 CPU 캐시에 적합하지 않습니다. 1024 차원의 10M 벡터 int8 인덱스는 10GB입니다. 후보를 스코어링하려면 DRAM에서 데이터를 스트리밍해야 하는데, 바로 이 부분에서 벌크 스코어링 아키텍처가 중요한 역할을 합니다.</p><p>일괄 스코어링 중 CPU 내부에서 발생하는 일을 측정하기 위해 하드웨어 성능 카운터를 사용했으며, 메모리 지연 시간을 숨기려면 아키텍처별로 하나씩, 근본적으로 다른 두 가지 전략이 필요하다는 것을 발견했습니다.</p><p><strong>x86에서는 명시적 프리페칭을 통해 캐시 미스를 방지할 수 있습니다. </strong>벌크 커널은 벡터를 순차적으로 처리하며, 다음 배치에 대한 프리페칭 명령어를 발행하면서 이전 배치가 완전히 계산된 후에 다음 배치를 처리합니다. 따라서 CPU가 데이터를 필요로 하기 전에 미래에 쓰일 데이터를 미리 L1 캐시로 끌어옵니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt368f29b5143d0f5a/6a1701dcc1e8a51780f8817b/a39548f8060c2a4a5154521a4047dd92d8cd77be-1580x309.png" alt="x86(AMD Turin) — int8 연산당 하드웨어 카운터'라는 제목의 표는 L1 캐시 미스, IPC, dTLB 미스에 대한 단일 모드와 벌크 모드를 비교하고, 해당 개선 요소를 보여줍니다." /><p>ARM에서는 프리페칭을 사용하더라도 동일한 순차적 접근 방식의 성능이 저조했습니다. 대신 <strong>벌크 커널</strong>은 매 스트라이드 위치마다 4개의 벡터에서 로드를 인터리브하여 순서에 상관없이 실행되는 엔진에 4개의 독립적인 메모리 스트림을 제공합니다. CPU는 데이터를 더 빠르게 가져오는 것이 아니라 메모리 요청이 처리되는 동안 항상 다른 계산 작업을 수행할 수 있으므로 대기 시간을 줄입니다. 자세한 분석은 <a href="https://github.com/elastic/elasticsearch/issues/145412">이 GitHub 이슈</a>에서 확인할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8751ac5b20b75508/6a1701deab7f08db83db9d13/832de3bc0d556a493b7bf3f250196018acfc1585-1580x238.png" alt="'ARM(Graviton 4) — int8 연산당 하드웨어 카운터'라는 제목의 표는 L1 캐시 미스 및 백엔드 스톨에 대한 단일 모드와 벌크 모드를 비교하고 해당 개선 사항을 설명합니다." /><p>수치는 두 가지 다른 이야기를 들려줍니다.</p><ol><li><p>x86에서는 프리페칭을 통해 139,000개의 캐시 미스가 19,000개로 줄어들고, 사이클당 명령어 수(IPC)는 두 배 이상 증가합니다. 프리페칭은 점점 더 비용이 많이 드는 DRAM 왕복을 숨겨주기 때문에 데이터 세트 크기가 커질수록 이러한 이점은 더욱 커져 L2 캐시에서는 1.2배, L3 이상에서는 2.8배에 이릅니다.</p></li><li><p>ARM에서는 캐시 미스는 거의 변하지 않습니다. 달라지는 것은 활용률입니다. 인터리브 액세스 패턴 덕분에 파이프라인에 데이터가 지속적으로 공급되어 백엔드 스톨이 40% 감소합니다. 데이터가 캐시에서 오든 DRAM에서 오든 메모리 수준 병렬 처리가 적용되므로 이러한 이점은 데이터 세트 크기와 관계없이 1.8배로 일관되게 유지됩니다.</p></li></ol><p>두 가지 아키텍처, 두 가지 전략, 하나의 결과: 프로덕션 규모에서 simdvec은 벡터가 메인 메모리에 분산되어 있더라도 CPU 파이프라인을 계속 바쁘게 유지합니다.</p><h2>Elasticsearch 사용자에게 의미하는 바</h2><p>이러한 커널 수준 기능은 복합적으로 작용합니다. 단일 벡터 검색 쿼리는 수백만 개의 거리 연산(HNSW 그래프 탐색, 후보 스코어링, 순위 재지정)을 수행할 수 있습니다. 수천 개의 동시 쿼리에서 연산당 나노초 단위의 차이는 쿼리 지연 시간과 클러스터 처리량에 직접적인 영향을 미칩니다. float32, int8, bfloat16 또는 BBQ를 사용하든, 인덱스가 메모리에 있든 디스크에 있든, simdvec은 그 기반 엔진이며, 이러한 모든 연산은 마지막 나노초까지 최적화된 동일한 엔진을 통해 실행됩니다.</p><p>핵심은 프로덕션 규모에서 벡터 검색 성능이 주로 원시 SIMD 처리량에 의해 결정되는 것이 아니라는 점입니다. 시스템이 얼마나 효율적으로 메모리 지연 시간을 숨기면서 수백만 개의 소규모 연산에 걸쳐 컴퓨팅을 유지하느냐에 따라 결정됩니다.</p><p>simdvec 커널은 거의 모든 Elasticsearch 릴리즈에서 개선됩니다. 새로운 양자화 유형과 하드웨어 플랫폼이 등장하면 첫날부터 최적화된 커널이 제공됩니다. 또한 기존 유형은 이미 출시된 구현을 개선하면서 계속해서 빨라집니다.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-vector-search-simdvec-engine</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-vector-search-simdvec-engine</guid>
    <category><![CDATA[벡터 데이터베이스]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Chris Hegarty,Lorenzo Dematte,Simon Cooper]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta18088409621369b/6a1701dfdc55de7297e00c8b/df9646091bafbbf0a6dfd212ff8a6bd1e8589708-1280x720.png" length="0" type="image/png"/>
    <pubDate>Thu, 23 Apr 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Kibana 대시보드 읽기 전용 권한 출시 안내]]></title>
    <description><![CDATA[Kibana에 읽기 전용 대시보드 기능이 도입되었습니다. 이제 대시보드 작성자는 세분화된 공유 제어 기능을 통해 분석 결과의 정확성을 유지하고 의도치 않은 변경으로부터 데이터를 안전하게 보호할 수 있습니다.]]></description>
    <content:encoded><![CDATA[<p>누구나 한 번쯤 겪어보셨을 상황입니다. 로그를 모니터링하기 위해 모든 차트와 필터, 레이블 하나하나에 공을 들여 완벽한 대시보드를 만드는 데 한 시간을 투자했다고 가정해 봅시다. 그렇게 만든 대시보드를 팀과 공유합니다. 며칠 후 대시보드를 다시 열어보니 무언가 잘못되어 있습니다. 동료가 쿼리를 살짝 수정했거나, 누군가 날짜 범위를 변경했을 수 있습니다. 아마도 도움을 주려던 의도였겠지만 결국 여러분은 수정 내역을 일일이 뒤져가며 모든 숫자를 다시 확인해야 하는 상황에 놓이게 됩니다. 익숙한 상황인가요?</p><p>이것이 바로 우리가 <strong>읽기 전용 대시보드</strong>를 개발한 이유입니다. 여러분이 기다려온 바로 그 제어 기능입니다. 이제 편집 권한이 있는 다른 사용자가 대시보드를 수정하거나 손상시킬 걱정 없이 안심하고 공유하세요.</p><p>참고: 읽기 전용 권한은 Elastic Cloud Serverless에서 사용할 수 있으며 Elastic Cloud Hosted 및 Elastic 자체 관리형의 경우 버전 9.3부터 제공됩니다.</p><h2>“모든 사람이 편집할 수 있을 때 방해가 되는 경우”</h2><p>그동안 Kibana에서의 <em>공유</em>는 보통 스페이스 수준의 권한을 의미했습니다. 특정 스페이스에서 대시보드를 생성할 수 있는 사용자라면 다른 사용자의 대시보드 역시 편집하거나 삭제할 수 있었습니다. 이는 협업에는 유용하지만 예기치 못한 문제를 일으키기도 합니다. 단 한 번의 편집 실수가 잘못된 의사결정이나 신뢰 상실로 이어지고 막대한 복구 작업이 필요해질 수 있기 때문입니다.</p><p>그동안 <strong>"대시보드 이름에 '읽기 전용'이라고 적어두고 사용자들이 제발 알아봐 주기만을 바란다"</strong>는 식의 임시방편들을 많이 봐왔습니다. 혹은 <strong>"태그를 달아두고 아무 일 없기를 간절히 기도한다"</strong>는 분들도 계셨죠. 하지만 이러한 막연한 기대는 제대로 된 권한 관리 모델이 아닙니다. 여러분에게는 스페이스 접근 권한을 완전히 막지 않고도 대시보드만 확실하게 잠글 수 있는 실질적인 방법이 필요했습니다.</p><h2>실제로 어떤 문제가 발생할까요?</h2><p>데브와 케빈은 모두 운영 스페이스 내 로그 모니터링 대시보드에 대한 편집 권한을 가지고 있습니다. 케빈이 차트를 일부 변경합니다. 나중에 데브가 확인했을 때 대시보드의 숫자는 그녀가 제시했던 수치와 일치하지 않습니다. 결국 무엇이 변경되었는지(종종 기억에 의존하여) 일일이 추적하여 수정해야 하며 잘못된 데이터가 포함된 보고가 얼마나 많이 배포되었는지 우려하게 됩니다.</p><h2>읽기 전용 대시보드: 합리적인 소유권과 제어</h2><p>읽기 전용 대시보드는 다른 사용자의 편집 허용 여부를 직접 결정할 수 있는 제어 기능을 제공하여 이 문제를 해결합니다. 대시보드를 공유할 때 <strong>편집</strong>(기본 설정, 기존과 동일) 또는 <strong>보기</strong> 중 하나를 선택할 수 있습니다. <strong>보기</strong> 모드에서는 작성자 본인과 Kibana 관리자만 대시보드를 수정하거나 삭제할 수 있습니다. 그 외 모든 사용자는 대시보드를 열어보고 활용하며 데이터를 신뢰할 수 있지만 임의로 수정할 수는 없습니다.</p><h3>주요 혜택</h3><ul><li><p><strong>대시보드 무결성:</strong> <strong>보기</strong> 모드에서는 해당 스페이스의 편집 권한이 있는 다른 사용자라도 대시보드를 수정하거나 삭제할 수 없습니다. 만약 시도할 경우에는 대시보드가 잠겨 있다는 안내가 표시됩니다. 여러분의 차트와 로직은 그대로 유지됩니다.</p></li><li><p><strong>주도권 유지:</strong> 여러분이 소유자입니다. 소유자는 언제든지 편집하고 세부 조정하거나 업데이트할 수 있습니다. 보기 전용으로 공유한다고 해서 소유자의 권한까지 제한되는 것은 아닙니다. 다만, 다른 사용자가 보게 되는 버전만 고정할 뿐입니다.</p></li><li><p><strong>유연한 라이프사이클:</strong> 언제든지 대시보드를 "편집 가능" 상태로 전환할 수 있습니다. 또한 Kibana 관리자는(예: 소유자가 퇴사하는 경우) 모든 대시보드를 지속적으로 관리할 수 있습니다. 관리의 공백이 발생하지 않습니다.</p></li></ul><p>이제 최종 확정된 핵심 업무용 대시보드를 안심하고 광범위하게 공유하며 데이터의 일관성을 유지할 수 있습니다. 이 기능은 Serverless를 포함한 <strong>모든 Elastic 티어 및 서비스 모델</strong>에서 사용할 수 있습니다.</p><h3>권한별 기능 안내</h3><p>역할별 권한 요약:</p><ul><li><p><strong>대시보드 소유자:</strong> 직접 생성한 대시보드이므로 소유자가 모든 편집 권한을 가집니다.</p></li><li><p><strong>Kibana 관리자:</strong> 모든 대시보드를 관리할 수 있습니다.</p></li><li><p><strong>스페이스 편집 권한이 있는 사용자:</strong> 자신의 대시보드를 생성하고 편집할 수 있습니다. 보기 전용 대시보드는 편집하거나 삭제할 수 없습니다.</p></li><li><p><strong>스페이스 보기 권한 사용자:</strong> 대시보드 목록 확인 및 조회만 가능합니다.</p></li></ul><p>작업</p><p>대시보드 소유자</p><p>Kibana 관리자</p><p>스페이스 편집 권한 사용자</p><p>스페이스 보기 권한 사용자</p><p>대시보드 목록 및 보기</p><p>✔</p><p>✔</p><p>✔</p><p>✔</p><p>새 대시보드 생성</p><p>✔</p><p>✔</p><p>✔</p><p>✘</p><p>편집 가능한 대시보드 수정/삭제</p><p>✔</p><p>✔</p><p>✔</p><p>✘</p><p>읽기 전용 대시보드 수정/삭제</p><p>✔</p><p>✔</p><p>✘</p><p>✘</p><h2>읽기 전용 모드 활성화 방법</h2><p>새 대시보드를 저장할 때 또는 나중에 공유 메뉴에서 보기 전용으로 설정할 수 있습니다.</p><h3>새 대시보드를 저장하는 경우</h3><ul><li><p>대시보드를 구성한 후 <strong>저장 버튼</strong>을 클릭합니다.</p></li><li><p>"새 대시보드로 저장" 모달에서 <strong>권한</strong>을 찾습니다.</p></li><li><p><strong>편집 가능</strong> 에서 <strong>보기 가능</strong>으로 변경합니다.</p></li><li><p><strong>저장</strong>을 클릭하면 끝입니다. 이제 다른 모든 사용자에게는 읽기 전용으로 표시됩니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt120724e3b963289f/6a16f76354abb858cd133baf/42a71d1bb55f9d50bd079f53bf45a0e1999b27f7-1214x1306.png" alt=" 대시보드 저장 옵션 중 보기 전용 권한이 선택된 Kibana 대화 상자 모습입니다." /><h2>이미 소유하고 있는 대시보드의 경우</h2><ul><li><p>대시보드를 엽니다.</p></li><li><p><strong>대시보드 공유</strong> 메뉴를 엽니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8fa2f365687c2ca8/6a16f764a292990e4bd00e01/e8405938557c879b1d4c262b98cf5a7f66408c04-1246x264.png" alt="편집 모드 종료, 공유, 설정 조정, 패널 추가, 저장 옵션이 표시된 Kibana 대시보드 툴바이며 공유 버튼이 강조되어 있습니다." /><ul><li><p>공유 모달에서 <strong>권한</strong>을 찾아 <strong>보기 가능</strong>으로 전환합니다. 변경 사항은 즉시 적용되며, 해당 스페이스의 다른 사용자는 더 이상 대시보드를 수정하거나 삭제할 수 없습니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05e6051dbe4b8250/6a16f76667045b321445bf9d/849405bc32701f3ebe0def012d8ae3cf3813ea0a-996x750.png" alt="대시보드 권한 및 보기 전용 링크 복사 옵션을 보여주는 Kibana 공유 패널입니다." /><ul><li><p><strong>공유</strong> 작업 위에 마우스를 올리면 해당 대시보드에 설정된 권한 유형을 바로 확인할 수 있습니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf8880996f84cdab3/6a16f7678b73cb3682189dfa/80541ddb1b1bc567b0aeff693944ea8b6871d6a7-1270x320.png" alt="공유 버튼이 강조된 Kibana 툴바이며 해당 스페이스의 모든 사용자가 대시보드를 볼 수 있음을 나타내는 툴팁이 표시되어 있습니다." /><h3>잠겨 있는 대시보드 식별</h3><p>메인 대시보드 목록에서 편집이나 삭제가 불가능한 대시보드는 선택 체크박스가 비활성화되어 있습니다. 이를 통해 어떤 항목이 보기 전용인지 한눈에 쉽게 확인할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9c5fae7fa018c89a/6a16f768b0367da1b172bacb/24b2eba08df86174db949c662e7886c5aea1b460-1999x876.png" alt="작성자, 타임스탬프와 함께 여러 대시보드가 표시된 Kibana 대시보드 목록에서 한 항목이 선택된 모습입니다." /><p>대시보드에서 편집 작업이 비활성화되며 해당 대시보드가 보기 전용으로 설정되었음을 안내하는 툴팁이 표시됩니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt50ef3c91d5640c0c/6a16f76a60084b08fc3c434d/e0a2f9da6dc854e876fc6dc2a7c3ef8b313b52ef-1358x330.png" alt="Kibana 대시보드 툴바의 편집 버튼에 사용자가 대시보드 수정 권한이 없음을 알리는 경고 툴팁이 표시됩니다." /><h2>직접 사용해 보기</h2><p>지금 바로 읽기 전용 대시보드를 이용해 보세요. 대시보드를 생성하고 <strong>보기 가능</strong>으로 설정한 뒤 공유하기만 하면 됩니다. 팀은 신뢰할 수 있는 단일 소스를 공유하게 되고 여러분은 안심할 수 있습니다. 이제 대시보드 제목에 "편집 금지"라고 적지 않아도 됩니다.</p><p>읽기 전용 대시보드를 어떻게 활용하고 계신지 여러분의 이야기가 궁금합니다. <a href="https://discuss.elastic.co">커뮤니티 포럼</a>에서 피드백을 공유하세요.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/kibana-dashboards-read-only-permissions</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/kibana-dashboards-read-only-permissions</guid>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Teresa Alvarez Soler]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta4d7f707011ca90f/6a16f76b8b73cb3125189dfe/11e578bc317aea30d2e10ccc0334a532f6af2ef9-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Thu, 26 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elasticsearch의 HNSW를 위한 적응형 조기 종료]]></title>
    <description><![CDATA[Elasticsearch의 HNSW를 위한 새로운 적응형 조기 종료 전략을 소개합니다.]]></description>
    <content:encoded><![CDATA[<p>Elasticsearch는 근접 그래프상에서 벡터 검색을 수행하기 위해 <a href="https://www.elastic.co/search-labs/blog/hnsw-graph">계층적으로 탐색 가능한 작은 세계</a>(HNSW) 알고리즘을 사용합니다. HNSW는 k-최근접 이웃(KNN) 결과의 품질과 그에 수반되는 비용 사이에서 훌륭한 절충안을 제공하는 것으로 알려져 있습니다.</p><p>HNSW에서 검색은 그래프 내의 후보 노드들을 반복적으로 확장하며, 현재까지 발견된 최근접 이웃의 제한된 집합을 유지하는 방식으로 진행됩니다. 각 확장 단계마다 비용(벡터 연산, 디스크 임의 탐색 등)이 발생하며, 검색이 진행될수록 그 비용 대비 얻게 되는 한계 이익은 점차 감소하는 경향이 있습니다.</p><p>HNSW 그래프 탐색을 최적화하는 한 가지 방법은, 새로운 진짜 이웃을 찾을 한계 확률이 더 이상 증가하지 않을 때 탐색을 중단하는 것입니다. 이러한 이유로, <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/index-modules#index-dense-vector-hnsw-early-termination">Elasticsearch 9.2</a>에서는 새로운 <a href="https://www.elastic.co/search-labs/blog/hnsw-knn-search-early-termination">조기 종료 메커니즘</a>을 도입했습니다. 이 방식은 그래프 노드를 방문해도 새로운 최근접 이웃을 충분히 찾지 못하는 상태가 고정된 횟수만큼 연속으로 발생하면 검색 프로세스를 중단합니다.</p><p>이 글은 다양한 데이터 세트와 데이터 분포에 더 잘 대응할 수 있도록, HNSW의 조기 종료 메커니즘을 개선한 방법을 안내합니다.</p><h2><strong>HNSW의 조기 종료</strong></h2><p>HNSW에서 검색은 근접 그래프 내의 후보 노드들을 반복적으로 확장하며, 현재까지 발견된 근접 이웃의 제한된 집합을 유지하는 방식으로 진행됩니다. 이는 그래프 전체를 방문하거나 특정 조기 종료 기준을 충족할 때까지 계속됩니다.</p><p>따라서 조기 종료는 반드시 항상 최적화를 위한 선택 사항인 것만은 아닙니다. <strong>검색 알고리즘 그 자체의 일부입니다</strong>. 탐색을 중단하기로 결정하는 그 순간이 효율성과 재현율 사이의 균형을 결정합니다. Elasticsearch에는 이미 HNSW 쿼리가 조기 종료될 수 있는 몇 가지 방법이 존재합니다.</p><ul><li><p>방문하는 노드의 최대 개수는 정해져 있습니다.</p></li><li><p>정해진 제한 시간에 도달했습니다.</p></li></ul><p>이러한 규칙들은 단순하고 예측 가능하지만, <strong>검색이 실제로 어떻게 진행되고 있는지에 대해서는 대체로 무관심합니다</strong>. 또한, 이러한 규칙들은 주로 최종 사용자에게 적절한 시간 내에 쿼리가 완료되도록 하기 위한 용도로 사용됩니다.</p><p><a href="https://www.elastic.co/search-labs/blog/hnsw-knn-search-early-termination">이전 블로그 게시물</a>에서 HNSW의 중복성이라는 개념을 소개한 바 있습니다. 요약하자면, HNSW가 새로운 최근접 이웃을 찾아내지 못하는 새로운 후보 노드들을 계속해서 평가할 때 중복 계산이 발생합니다.</p><h2><strong>인내심: 노력이 아닌 진척도를 측정하기</strong></h2><p><em>인내심</em>이라는 개념은 조기 종료의 기준을 <strong>노력이 아닌 진전</strong>을 중심으로 재정의합니다.</p><p>다음과 같은 질문을 던지는 대신:</p><p>“우리가 몇 걸음을 걸었습니까?”</p><p>새로운 질문은 다음과 같습니다:</p><p>“더 나은 결과를 찾을 가망이 없다고 판단하기까지, 얼마만큼의 연산 낭비를 감수할 수 있을까요?"</p><p>HNSW 검색 과정에서, 초기 탐색은 일반적으로 top-k 후보 집단에 대해 가장 비약적인 개선을 만들어냅니다. HNSW 그래프 탐색의 첫 단계에서는, 알고리즘이 쿼리 벡터에 점점 더 가까운 이웃들을 계속해서 발견함에 따라 이웃 집합이 계속해서 업데이트됩니다. 시간이 흐름에 따라, 검색이 수렴하면서 이러한 개선은 점차 드물어집니다. <a href="https://cs.uwaterloo.ca/~jimmylin/publications/Teofili_Lin_ECIR2025.pdf">인내심 기반 종료</a>는 이러한 패턴을 모니터링하며, 개선이 일정 기간 지속적으로 발생하지 않으면 검색을 종료합니다.</p><p>실제로 HNSW 그래프를 방문하는 동안, 후보 노드들을 거쳐 가며 큐 포화도를 함께 계산합니다. 이는 가장 최근의 그래프 노드를 방문하는 동안 변경되지 않고 그대로 남은 근접 이웃의 비율(또는 마지막 반복 과정에서 새로 추가된 이웃 수의 역수)을 측정합니다. 이러한 비율이 너무 많은 연속된 반복 과정 동안 과도하게 높아지면, 더 이상의 그래프 방문을 중단합니다</p><p>개념적으로 볼 때, 인내심은 HNSW 검색을 <strong>수익 체감의 과정</strong>으로 취급합니다. 수익이 정체되는 시점에 도달하면, 그래프를 계속해서 탐색하는 것은 실질적인 이익을 거의 주지 못합니다.</p><p>이러한 프레이밍은 강력합니다. 종료 시점을 임의로 정해진 고정된 한계치가 아니라, <em>관찰 가능한 결과</em>에 직접 연결하기 때문입니다.</p><p>이러한 스마트 조기 종료 기술을 사용하면, 거의 완벽한 상대적 재현율을 유지하면서도 HNSW 그래프 탐색 과정에서 방문하는 노드 수를 줄일 수 있다는 장점이 있습니다.</p><p>이를 시각화하기 위해, 몇 가지 데이터 세트인 FinancialQA, Quora과 모델인 JinaV3, E5-small 조합을 대상으로 인내심 기반 조기 종료(<em><code>et=static</code></em>와 HNSW 기본 작동 방식(<em><code>et=no</code></em>)을 비교하여, 방문한 노드 수에 따른 재현율의 변화량을 그래프로 그려볼 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfd0d692b9beb476a/6a170ef4dc55debf0be00e97/a9d07c5153ea64a2426c82487c36846030692bb9-1600x945.png" alt="HNSW를 위한 적응형 조기 종료 " /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt93509c251a1b641e/6a170ef6dc55dea2b3e00e9b/dac56125c4b16d1b596c9876b6ca9ac7b2dc87fa-1600x944.png" alt="HNSW es를 위한 적응형 조기 종료" /><h2><strong>정적 임계값 및 HNSW 동역학</strong></h2><p>실제로, Elasticsearch는 이를 <strong>정적 임계값</strong>을 사용하여 구현했습니다. 하나의 임계값은 <strong>포화 임계값</strong>입니다. 이는 우리가 차선이라고 간주하는 포화 비율을 의미합니다. 또 다른 임계값은 <strong>인내심 임계값</strong>입니다. 이는 큐 포화도가 여전히 낮은 상태임에도, 방문을 계속 허용할 연속적인 그래프 노드 방문 횟수를 의미합니다.</p><p>Elasticsearch 9.2에 이 조기 종료 전략을 도입할 당시, 지연 시간과 메모리 소모 측면에서 이득을 보면서도 재현율은 최대한 유지할 수 있도록 보수적인 기본값을 선택하기로 결정했습니다. 이러한 이유로, 포화 임계값을 100%로 설정하고, 인내심 임계값은 KNN 쿼리에서 <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-knn-query#knn-query-top-level-parameters:~:text=search%20request%20size.-,num_candidates,-(Optional%2C%20integer)%20The"><em><code>num_candidates</code></em></a>의 30% 수준(상한선 제한 있음)으로 설정했습니다.</p><p>많은 시나리오에서 이러한 설정들이 잘 작동하기도 했지만, 동일한 수의 이웃을 요청하는 두 쿼리라도 그 수렴 동작은 근본적으로 다를 수 있습니다. 어떤 쿼리는 밀집된 지역 이웃을 만나 빠르게 포화 상태에 도달하는 반면, 다른 쿼리는 경쟁력 있는 후보군을 찾기까지 길고 희소한 경로를 통과해야만 합니다. 후자가 효과적으로 처리하기 가장 어려운 것으로 나타났습니다.</p><p>그 결과, 때때로 다음과 같은 현상들이 관찰되었습니다:</p><ul><li><p>쉬운 쿼리에 대한 과도한 탐색.</p></li><li><p>까다로운 쿼리에 대한 조기 종료.</p></li></ul><p>따라서 고정된 임계값이 수렴에 대한 일괄적인 가정을 전제로 하는 반면, HNSW가 다양한 동역학에 더 잘 적응하도록 만들 수 있다는 점을 깨달았습니다.</p><h2><strong>HNSW 조기 종료 적응형 구현</strong></h2><p>적응형 조기 종료는 이 문제에 대해 기존과는 다른 각도에서 접근합니다. 미리 정의된 중단 임계값을 강제하는 대신, 알고리즘은 <strong>검색 역학 자체로부터 언제 멈춰야 할지를 추론합니다</strong>.</p><p>따라서 연속된 두 후보 사이의 큐 포화율을 비교하는 대신, 그래프 방문 중의 (<a href="https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm">웰포드 알고리즘을 사용한</a>) 이동 평균  및 표준 편차 와(과) 함께, 순간 평활 발견율 (마지막 방문 <em>i</em>에서 쿼리 <em>q</em>에 대해 도입된 새로운 이웃의 수)를 도입하기로 결정했습니다. 발견율에 관한 이러한 통계치들은 각 쿼리당 개별적으로 계산됩니다. 이 정보를 사용하여 각 쿼리의 특성에 맞춰 서로 다른 수준의 인내심을 적용할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdbfb1e123f1b026d/6a170ef7cf4f25d9bab2d216/1958be7ca4425ade66eaf621ada3533173183598-694x118.png" alt="" /><p>이전의 정적 임계값들은 이제 발견율 통계에 따라 적응형으로 변합니다. 포화 임계값은 이동 평균에 표준 편차를 더한 값이 되며, 인내심 수치는 표준 편차에 반비례하여 적응하고 확장되도록 만들었습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7d4d91f464a9dc9d/6a170ef8d7c0223420de656a/f7ee4a55c24853b657df26052b275e8bd76cf0f9-654x156.png" alt="" /><p>조기 종료 규칙은 기존과 동일하게 유지됩니다. 즉, 순간 발견율이 적응형 포화 임계값보다 낮아질 때 포화가 발생합니다. 포화 상태가 적응형 인내심보다 더 많은 횟수의 연속적인 후보 방문 동안 지속되면, 그래프 방문이 중단됩니다</p><p>이러한 방식을 통해, KNN 쿼리의 <em><code>num_candidates</code></em> 매개변수(조기 종료 여부와 상관없이 항상 설정되어 있거나 기본값으로 남겨지는 값)에 의존하지 않으면서도, 각 쿼리와 벡터 분포에 맞춰 동적으로 더 잘 적응하는 동작을 구현할 수 있습니다.</p><p>FinancialQA 및 Quora에서 적응형 전략(<em><code>et=adaptive</code></em>)의 방문 노드당 재현율은 정적 전략(<em><code>et=static</code></em>) 및 기본 HNSW 동작(<em><code>et=no</code></em>)과 비교했을 때 더 높은 수치를 나타냅니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blteab7ba53ae14da0e/6a170ef9961e69e072c4cfd5/2a906997d9a25d74c7038bd9661bc97581e7258e-1600x938.png" alt=" 적응형 전략 및 기본 HNSW 동작" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6fb9e672d3698200/6a170efb67045b7b2b45c2ab/3a114911e232c351dbb814cea20e8b0f1415a717-1600x925.png" alt="" /><p>적응형 조기 종료는 Elasticsearch 9.3부터 HNSW 밀집 벡터 필드에 기본으로 활성화되며, <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/index-modules#index-dense-vector-hnsw-early-termination">동일한 인덱스 수준 설정</a>을 통해 나중에 비활성화할 수도 있습니다.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hnsw-elasticsearch-adaptive-early-termination</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hnsw-elasticsearch-adaptive-early-termination</guid>
    <category><![CDATA[벡터 데이터베이스]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Tommaso Teofili]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt27b746cc1995e6b7/6a170efda29299de8ad010c6/e6d3186f609dd56dc5ffe33d70fa9e5cfa05b51f-1280x720.png" length="0" type="image/png"/>
    <pubDate>Mon, 02 Mar 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA['best_compression'으로 검색 성능 개선]]></title>
    <description><![CDATA['best_compression'은 일반적으로 Elastic Observability 및 Elastic Security 사용 사례에서 저장 공간을 절약하는 기능으로 간주되지만, 이 블로그에서는 검색의 성능 조정 수단으로써 그 효과를 보여줍니다.]]></description>
    <content:encoded><![CDATA[<p></p><p>동시성이 높은 워크로드에 맞게 Elasticsearch를 조정할 때 일반적인 접근 방식은 검색 지연 시간을 줄이기 위해 작업 문서 세트를 메모리에 유지하도록 RAM을 최대화하는 것입니다. 따라서 <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/index-modules"><code>best_compression</code></a> 은(는) 주로 저장 공간 효율성이 우선시되는 Elastic Observability와 Elastic Security 사용 사례에서 저장 공간 절약 수단으로 간주되며, 검색 워크로드에는 거의 고려되지 않습니다.</p><p>이 블로그에서는 데이터 세트 크기가 OS 페이지 캐시를 크게 초과하는 경우, <code>best_compression</code> 이(가) I/O 병목 현상을 줄여 검색 성능과 리소스 효율성을 개선하는 방법을 보여줍니다.</p><h2><strong>설정</strong></h2><p>해당 사용 사례는 <a href="https://www.elastic.co/docs/deploy-manage/deploy/elastic-cloud/ec-change-hardware-profile#ec-profiles-compute-optimized-arm">Elastic Cloud CPU에 최적화된 인스턴스</a>에서 실행되는 동시성이 높은 검색 애플리케이션입니다.</p><ul><li><p>데이터 볼륨: 약 5억 개의 문서</p></li><li><p>인프라: 6개의 Elastic Cloud(Elasticsearch Service) 인스턴스(각 인스턴스: 1.76TB 저장 공간 | 60GB RAM | 31.9 vCPU)</p></li><li><p>메모리 대 저장 공간 비율: 전체 데이터 세트의 약 5%를 RAM에 저장</p></li></ul><h2><strong>증상: 긴 지연 시간</strong></h2><p>19시경에 현재 요청 수가 급증할 때 검색 지연 시간이 크게 악화되는 것을 확인했습니다. 그림 1과 그림 2에서 볼 수 있듯이, Elasticsearch 인스턴스당 분당 약 400건의 요청이 발생하는 최고 트래픽 수준에서 평균 쿼리 서비스 시간은 60ms 이상으로 저하되었습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf8ab7de934d6b410/6a170440c1e8a58db3f881c1/f9c6cc1882e7db24336c65c54bbc1d38dcdb7fa3-697x311.png" alt="Elasticsearch당 분당 요청 수가 최고치를 기록했습니다" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt32de2bed0afbacd5/6a1704422b835fa5ddf4b0e2/bbb705ae2fcd14c81d335bf322346caf3bf33765-996x618.png" alt="Elasticsearch의 평균 쿼리 서비스 시간" /><p>초기 연결 처리 이후 CPU 사용량은 비교적 낮은 수준을 유지했는데, 이는 컴퓨팅이 병목 현상이 아님을 나타냅니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5b45d4a1ff48f54/6a17044447d49cd7252d88af/cec15a28d2d22e9adedd2951bb2334b3717890a1-1494x730.png" alt="Elasticsearch CPU 사용량" /><p>쿼리 볼륨과 페이지 오류 사이에 강한 상관관계가 나타났습니다. 요청량이 증가함에 따라 페이지 오류도 비례적으로 증가하여 분당 약 40만 건에 달하는 최고치를 기록했습니다. 이는 활성 데이터 세트가 페이지 캐시에 저장될 수 없음을 의미합니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd0a3d0c610700bdb/6a17044560084b6f403c4459/511f2f10300a9d10ba3d7a82b9a8c8d567ac5636-1492x678.png" alt="페이지 오류 수와 Elasticsearch 성능" /><p>동시에 JVM 힙 사용량은 정상적인 수준을 보였습니다. 이는 가비지 컬렉션 문제가 아님을 시사하며, 병목 현상이 I/O에 있음을 확인시켜 줍니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3f888a03ce78eb04/6a170448964cea401008ba59/336bbad638f866304358dba1d06ee987de0f23cf-1490x568.png" alt="Elasticsearch에서 힙 사용량" /><h2><strong>진단: I/O 바운드</strong></h2><p>시스템이 I/O 바운드 상태였습니다. <a href="https://www.elastic.co/blog/elasticsearch-caching-deep-dive-boosting-query-speed-one-cache-at-a-time">Elasticsearch는 OS 페이지 캐시를 활용하여 메모리에서 인덱스 데이터를 제공합니다</a>. 인덱스가 캐시에 비해 너무 크면 쿼리는 값비싼 디스크 읽기를 트리거합니다. 일반적인 해결책은 수평적 확장(노드/RAM 추가)이지만, 먼저 기존 리소스를 활용하여 효율성을 개선하고자 했습니다.</p><h2><strong>수정 사항</strong></h2><p>기본적으로 Elasticsearch는 인덱스 세그먼트에 <a href="https://en.wikipedia.org/wiki/LZ4_(compression_algorithm)">LZ4</a> 압축을 사용하여 속도와 크기 사이의 균형을 유지합니다. <code>best_compression</code> ( <a href="https://en.wikipedia.org/wiki/Zstd">zstd</a> 방식 사용)로 전환하면 인덱스 크기가 줄어들 것이라는 가설을 세웠습니다. 설치 공간이 작아지면 페이지 캐시에 더 많은 비율의 인덱스가 들어갈 수 있으므로 압축 해제에 필요한 CPU 사용량의 미미한 증가와 디스크 I/O의 감소를 맞바꿀 수 있습니다.</p><p><code>best_compression</code> 을(를) 활성화하기 위해 인덱스 설정 <code>index.codec: best_compression</code> (으)로 데이터를 다시 색인했습니다. 또는 인덱스를 닫고 인덱스 코덱을 <code>best_compression</code> (으)로 재설정한 다음 세그먼트 병합을 수행해도 동일한 결과를 얻을 수 있습니다.</p>POST my-index/_close
PUT my-index/_settings
{
    "codec": "best_compression"
}
  
POST my-index/_open  
POST my-index/_forcemerge?max_num_segments=1<h2><strong>결과</strong></h2><p>결과는 가설을 뒷받침했습니다. 저장 공간 효율성 개선은 CPU 사용률의 증가 없이 검색 성능의 상당한 향상으로 직결되었습니다.</p><p><code>best_compression</code> 을(를) 적용함으로써 인덱스 크기가 약 25% 감소했습니다. 반복적인 로그 데이터에서 나타난 감소율보다는 낮지만, 이 25% 감소는 페이지 캐시 용량을 동일한 수준으로 실질적으로 증가시켰습니다.</p><p>다음 로드 테스트(17시 시작) 동안 트래픽은 훨씬 더 높아져 Elasticsearch 노드당 분당 최대 500건의 요청을 기록했습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta61ab3bd5ded5716/6a170449a6c2b9f711e795dd/fc1902f396cb2115c0013155ad07f6eb87389c60-660x309.png" alt="Elaticserach에서 로드 테스트" /><p>로드가 높아졌음에도 CPU 사용률은 이전 실행보다 낮았습니다. 이전 테스트에서 사용률이 높았던 것은 과도한 페이지 오류 처리 및 디스크 I/O 관리로 인한 오버헤드 때문이었을 가능성이 큽니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9fd1a44b02a4f787/6a17044b2b835ff996f4b0e6/15699ef4c65b3f0a9f8a3e1bae8bb18f7b647025-819x352.png" alt="best_compression으로 Elasticsearch CPU 사용률 성능 개선" /><p>결정적으로 페이지 오류가 많이 감소했습니다. 처리량이 높아진 상황에서도 오류 수는 분당 20만 건 미만으로, 기준 테스트의 30만 건 이상에 비해 현저히 줄어들었습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltef0c621d76767115/6a17044c2b835fe49ef4b0ea/f76ca967976d740af88a9359b66041701abb46fc-764x340.png" alt="best_compression으로 페이지 오류 수 및 Elasticsearch 성능 개선" /><p>페이지 오류 결과는 여전히 최적에 미치지 못했지만, 쿼리 서비스 시간은 약 50% 단축되었습니다. 로드가 많은 상황에서도 30ms 미만으로 유지되었습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6579b3d005d04101/6a17044e66c4f9179cf8bf13/750ec1c59b8eb5069aed4c066d856ecea82d5bca-620x311.png" alt="best_compression으로 Elasticsearch의 평균 쿼리 서비스 시간 성능 개선" /><p></p><h2><strong>결론: 검색을 위한 best_compression</strong></h2><p>데이터 볼륨이 사용 가능한 물리적 메모리를 초과하는 검색 사용 사례에서 <code>best_compression</code>은(는) 강력한 성능 조정 수단입니다.</p><p>캐시 미스를 해결하는 일반적인 해결책은 RAM을 늘려 확장하는 것입니다. 하지만 인덱스 공간을 줄임으로써 페이지 캐시의 문서 수를 최대화하는 동일한 목표를 달성했습니다. 다음 단계에서는 <a href="https://www.elastic.co/blog/space-savings-a-lesser-known-benefit-of-index-sorting-in-elasticsearch"><strong>인덱스 정렬</strong></a>을 통해 저장 공간 최적화를 더 강화하고 기존 리소스에서 성능을 극대화할 것입니다.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/improve-elasticsearch-performance-best-compression</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/improve-elasticsearch-performance-best-compression</guid>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Sherry Ger,Ryan Eno]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4ff57fbb95c04412/6a17044fab7f081490db9d66/5141a8c2618337207d848ce16b258a86885955b2-1600x1034.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 23 Jan 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[판단 목록을 사용하여 검색 쿼리의 관련성을 평가합니다.]]></title>
    <description><![CDATA[Elasticsearch에서 확장 가능한 검색 테스트를 위해 검색 쿼리 관련성을 객관적으로 평가하고 리콜과 같은 성능 메트릭을 개선하기 위해 판단 목록을 구축하는 방법을 살펴보세요.]]></description>
    <content:encoded><![CDATA[<p>검색 엔진을 개발하는 개발자들은 종종 같은 문제를 겪습니다. 비즈니스 팀이 특정 검색 결과에 만족하지 못하는데, 기대했던 문서가 검색 결과 상단이 아니라 3~4번째에 표시되기 때문입니다.</p><p>그러나 모든 케이스를 수동으로 테스트할 수 없기 때문에, 한 가지 문제를 해결하면 실수로 다른 쿼리가 손상될 수 있습니다. 하지만 특정 쿼리를 변경했을 때 다른 쿼리에 파급 효과를 미치는지 사용자 또는 QA 팀이 어떻게 테스트할 수 있을까요? 더 중요한 것은 변경 사항이 실제로 쿼리를 개선했는지 어떻게 확인할 수 있을까요?</p><h2>체계적인 평가를 향해</h2><p>이때 판단 목록이 유용하게 작용합니다. 변경할 때마다 수동 및 주관적 테스트에 의존하는 대신, 비즈니스 사례와 관련된 고정된 쿼리 세트와 해당 결과를 정의할 수 있습니다.</p><p>이 세트가 기준이 됩니다. 변경 사항을 구현할 때마다 검색이 실제로 개선되었는지 여부를 평가합니다.</p><p>이 접근 방식의 가치는 다음과 같습니다:</p><ul><li><p><strong>불확실성 제거</strong>: 변경 사항이 다른 쿼리에 영향을 미치는지를 데이터가 알려줍니다.</p></li><li><p><strong>수동 테스트 중지</strong>: 판단 세트가 기록되면 테스트가 자동으로 진행됩니다.</p></li><li><p><strong>변경 지원</strong>: 변경의 이점을 뒷받침하는 명확한 메트릭을 표시할 수 있습니다.</p></li></ul><h2>판단 목록을 만드는 방법</h2><p>가장 쉽게 시작하는 방법 중 하나는 대표 검색어를 선택하고 관련 문서를 수동으로 고르는 것입니다. 이 목록을 작성할 때 두 가지 방법을 사용할 수 있습니다.</p><ul><li><p><strong>이진 판단:</strong> 쿼리와 연관된 각 문서에 <em>관련 있음</em>(보통 점수 1)과 <strong>관련 없음</strong>(0)이라는 간단한 태그가 붙습니다.</p></li><li><p><strong>등급별 판단:</strong> 여기서는 문서마다 다른 수준의 점수가 매겨집니다. 예를 들어, <a href="https://en.wikipedia.org/wiki/Likert_scale">Likert 척도</a>와 유사하게 0~4 척도를 설정해 0은 '전혀 관련 없음', 4는 '매우 관련 있음'으로 정의하고, 그 사이에 '관련 있음', '어느 정도 관련 있음'과 같은 단계를 둘 수 있습니다.</p></li></ul><p>이진 판단은 '이 문서가 결과에 포함되어야 하는가?'처럼 검색 의도에 명확한 한계가 있을 때 잘 작동합니다.</p><p>등급별 판단은 결과가 애매한 영역이 있을 때 더 유용합니다. 어떤 결과는 다른 결과보다 더 좋으므로 '매우 좋음', '좋음', '쓸모없음' 결과를 얻고, 결과의 순서와 사용자의 피드백을 중요시하는 메트릭을 사용할 수 있습니다. 그러나 등급 척도는 검토자마다 점수 수준을 다르게 사용해 판단의 일관성이 떨어질 수 있다는 단점도 갖고 있습니다. 또한 등급별 메트릭은 점수가 높으면 가중치를 더 많이 부여하기 때문에 작은 변화(예: 4점 대신 3점으로 평가)로도 검토자가 의도한 것보다 훨씬 더 큰 변화를 일으킬 수 있습니다. 이렇게 주관적인 요소가 추가되면 시간이 지남에 따라 등급별 판단이 더 복잡하고 관리하기 어려워집니다.</p><h2>문서를 직접 분류해야 하나요?</h2><p>반드시 그렇지는 않습니다. 판단 목록을 만드는 데는 여러 가지 방법이 있고 각각 고유한 장점과 단점이 있기 때문입니다.</p><ul><li><p><strong>명시적 판단:</strong> 여기서 중소기업은 각 쿼리/문서를 검토하고 관련성 여부(또는 방법)를 수동으로 결정합니다. 이는 품질과 제어 측면에서 장점을 제공하지만 확장성이 떨어집니다.</p></li><li><p><strong>암묵적 판단:</strong> 이 방법은 클릭, 이탈률, 구매 등 실제 사용자 행동을 기반으로 관련 문서를 추론합니다. 이 방식을 사용하면 데이터를 자동으로 수집할 수 있지만 편향적일 수 있습니다. 예를 들어, 사용자들은 관련성이 없더라도 검색 결과 상단에 있는 항목을 더 자주 클릭하는 경향이 있습니다.</p></li><li><p><strong>AI 생성 판단:</strong> 이 마지막 옵션은 모델(예: LLM)을 사용하여 쿼리와 문서를 자동으로 평가하며, 흔히 <a href="https://en.wikipedia.org/wiki/LLM-as-a-Judge">LLM 배심원단</a>이라고도 합니다. 빠르고 쉽게 확장할 수 있지만, 데이터의 품질은 사용 중인 모델의 품질과 LLM 학습 데이터가 비즈니스 <a href="http://interests.as/">관심사</a>와 얼마나 잘 부합하는지에 달려 있습니다. 인간의 평가와 마찬가지로, LLM 배심원단 역시 편향이나 불일치를 도입할 수 있으므로 신뢰할 수 있는 소규모의 판단과 비교하여 결과를 검증하는 것이 중요합니다. LLM 모델은 본질적으로 확률적이기 때문에 <a href="https://www.ibm.com/think/topics/llm-temperature">온도</a> 파라미터를 0으로 설정해도 같은 결과에 대해 서로 다른 등급을 부여하는 경우가 많습니다.</p></li></ul><p>다음은 판단 세트를 만드는 가장 좋은 방법을 선택하기 위한 몇 가지 권장 사항입니다.</p><ul><li><p>가격, 브랜드, 언어, 스타일, 제품 세부정보 등 사용자만 제대로 판단할 수 있는 일부 기능의 중요도를 결정합니다. 중요한 사항이라면 최소한 <em>판단 목록</em>의 일부에 대한 <strong>명시적인 판단</strong>이 필요합니다.</p></li><li><p>검색 엔진 트래픽이 이미 충분하여 클릭, 전환, 체류 시간 등의 지표를 활용해 사용 추세를 파악할 수 있는 경우, <strong>암묵적 판단</strong>을 사용하세요. 하지만 편향(예: 사용자는 하위 순위의 결과가 더 관련성이 높더라도 상위 순위의 결과를 더 자주 클릭하는 경향이 있음)을 방지하기 위해 명시적인 판단 기준과 대조하여 신중하게 해석해야 합니다.</p></li></ul><p>이를 해결하기 위해, 위치 편향 제거 기술이 클릭 데이터를 조정하거나 가중치를 조정하여 사용자의 진정한 관심을 더 잘 반영합니다. 몇 가지 접근 방식은 다음과 같습니다.</p><ul><li><p><strong>결과 순서 변경</strong>: 일부 사용자를 대상으로 검색 결과 순서를 변경하여 순위가 클릭에 미치는 영향을 추정합니다.</p></li><li><p><strong>클릭 모델</strong>에는<a href="https://wiki.math.uwaterloo.ca/statwiki/index.php?title=a_Dynamic_Bayesian_Network_Click_Model_for_web_search_ranking">동적 베이지안 네트워크 </a><a href="https://wiki.math.uwaterloo.ca/statwiki/index.php?title=a_Dynamic_Bayesian_Network_Click_Model_for_web_search_ranking"><strong>DBN</strong></a>, <a href="https://rsrikant.com/papers/kdd10.pdf">사용자 브라우징 모델 </a><a href="https://rsrikant.com/papers/kdd10.pdf"><strong>UBM</strong></a>이 포함됩니다. 이러한 통계 모델은 스크롤, 체류 시간, 클릭 순서 및 결과 페이지로 돌아가는 등의 패턴을 사용하여 클릭이 단순한 위치가 아니라 실제 관심을 반영할 확률을 추정합니다.</p></li></ul><h2>예시: 영화 평점 앱</h2><h3>필수 구성 요소</h3><p>이 예시를 실행하려면 Elasticsearch 8.x 클러스터가 <a href="https://www.elastic.co/downloads/elasticsearch">로컬</a>이나 <a href="https://www.elastic.co/cloud/cloud-trial-overview">Elastic Cloud Hosted</a>(호스팅 또는 서버리스)를 실행하고, <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis">REST API</a> 또는 Kibana에 접근할 수 있어야 합니다.</p><p>사용자가 영화에 대한 의견을 업로드하고 볼 영화를 검색할 수 있는 앱을 생각해 보세요. 사용자들이 직접 작성한 글이기 때문에 오타가 있거나, 표현 방식이 다양할 수 있습니다. 따라서 검색 엔진은 이러한 다양성을 해석하고 사용자에게 유용한 결과를 제공할 수 있어야 합니다.</p><p>전반적인 검색 동작에 영향을 주지 않고 쿼리를 반복적으로 수정할 수 있도록, 비즈니스 팀에서 가장 빈번하게 발생하는 검색어를 기반으로 다음과 같은 이진 판단 기준을 만들었습니다.</p><p>쿼리</p><p>DocID</p><p>텍스트</p><p>디카프리오의 연기</p><p>doc1</p><p>디카프리오의 '레버넌트: 죽음에서 돌아온 자'에서의 연기는 놀라웠다.</p><p>디카프리오의 연기</p><p>doc2</p><p>인셉션에서는 레오나르도 디카프리오가 그의 가장 상징적인 연기를 보여줍니다.</p><p>디카프리오의 연기</p><p>doc3</p><p>브래드 피트는 이 범죄 스릴러에서 탄탄한 연기를 선보입니다.</p><p>디카프리오의 연기</p><p>doc4</p><p>놀라운 시각 효과와 함께 액션으로 가득한 모험을 경험할 수 있다.</p><p>눈물을 흘리게 하는 슬픈 영화</p><p>doc5</p><p>가슴 아픈 사랑과 상실에 대한 이야기로 몇 시간 동안 눈물을 흘렸습니다.</p><p>눈물을 흘리게 하는 슬픈 영화</p><p>doc6</p><p>휴지가 꼭 필요한 슬픈 영화</p><p>눈물을 흘리게 하는 슬픈 영화</p><p>doc7</p><p>웃음을 자아내는 경쾌한 코미디 영화</p><p>눈물을 흘리게 하는 슬픈 영화</p><p>doc8</p><p>액션과 흥분으로 가득 찬 SF 대작.</p><p>인덱스 생성:</p>PUT movies
{
  "mappings": {
    "properties": {
      "text": {
        "type": "text"
      }
    }
  }
}<p>대량 요청:</p>POST /movies/_bulk
{ "index": { "_id": "doc1" } }
{ "text": "DiCaprio performance in The Revenant was breathtaking." }
{ "index": { "_id": "doc2" } }
{ "text": "Inception shows Leonardo DiCaprio in one of his most iconic roles." }
{ "index": { "_id": "doc3" } }
{ "text": "Brad Pitt delivers a solid performance in this crime thriller." }
{ "index": { "_id": "doc4" } }
{ "text": "An action-packed adventure with stunning visual effects." }
{ "index": { "_id": "doc5" } }
{ "text": "A heartbreaking story of love and loss that made me cry for hours." }
{ "index": { "_id": "doc6" } }
{ "text": "One of the saddest movies ever made -- bring tissues!" }
{ "index": { "_id": "doc7" } }
{ "text": "A lighthearted comedy that will make you laugh." }
{ "index": { "_id": "doc8" } }
{ "text": "A science-fiction epic full of action and excitement." }<p>아래는 앱이 사용하는 Elasticsearch 쿼리입니다.</p>GET movies/_search
{
 "query": {
   "match": {
     "text": {
       "query": "DiCaprio performance",
       "minimum_should_match": "100%"
     }
   }
 }
}<h3>판단에서 지표로</h3><p>판단 목록은 그 자체로 많은 정보를 제공하지 않으며, 단지 쿼리 결과를 예상할 수 있을 뿐입니다. 그러나 검색 성능을 측정하기 위해 객관적인 메트릭을 계산할 때가 되면 판단 목록이 그 진가를 발휘합니다.</p><p>요즘 가장 많이 사용되는 메트릭은 다음과 같습니다.</p><ul><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-precision"><strong>정확도</strong></a><strong>: </strong>전체 검색 결과 중 실제 관련성이 있는 결과의 비율을 측정합니다.</p></li><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-recall"><strong>리콜</strong></a><strong>: </strong>검색 엔진이 찾은 x개의 결과 중에서 관련성 있는 결과의 비율을 측정합니다.</p></li><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#_discounted_cumulative_gain_dcg"><strong>할인 누적 이득(DCG):</strong></a>결과 순위의 품질을 측정하며, 가장 관련성이 높은 결과가 최상위에 있어야 한다고 판단합니다.</p></li><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#_mean_reciprocal_rank"><strong>평균 상호 순위(MRR):</strong></a> 첫 번째 관련 결과의 위치를 측정합니다. 목록에서 높은 위치에 있을수록 점수가 높아집니다.</p></li></ul><p>동일한 영화 평점 앱을 예로 들어 리콜 메트릭을 계산하여 쿼리에서 누락된 정보가 있는지 확인해 보겠습니다.</p><p>Elasticsearch에서는 <em>판단 목록</em>을 사용하여 <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval">순위 평가 API</a>를 통해 메트릭을 계산할 수 있습니다. 이 API는 판단 목록, 쿼리, 평가하려는 메트릭을 입력으로 받아 쿼리 결과와 판단 목록을 비교한 값을 반환합니다.</p><p>두 개의 쿼리에 대한 판단 목록을 실행해 보겠습니다.</p>POST /movies/_rank_eval
{
 "requests": [
   {
     "id": "dicaprio-performance",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "DiCaprio performance",
             "minimum_should_match": "100%"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc1",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc2",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc3",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc4",
         "rating": 0
       }
     ]
   },
   {
     "id": "sad-movies",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "sad movies that make you cry",
             "minimum_should_match": "100%"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc5",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc6",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc7",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc8",
         "rating": 0
       }
     ]
   }
 ],
 "metric": {
   "recall": {
     "k": 10,
     "relevant_rating_threshold": 1
     }
 }
}<p>'디카프리오' 쿼리와 '슬픈 영화' 쿼리, 두 가지 요청을 _rank_eval에 사용하겠습니다. 각 요청에는 쿼리와 해당 판단 목록(평가)이 포함됩니다. 평가에 포함되지 않은 문서는 판단이 없는 것으로 간주되므로 모든 문서에 등급을 매길 필요는 없습니다. 계산을 수행할 때 리콜은 평가에서 관련성이 있는 것으로 간주되는 문서인 '관련 세트'만 고려합니다.</p><p>이 경우, '디카프리오' 쿼리의 리콜은 1이고 '슬픈 영화'는 0입니다. 즉, 첫 번째 쿼리에서는 모든 관련 결과를 얻을 수 있었지만 두 번째 쿼리에서는 아무런 결과도 얻지 못했습니다. 따라서 평균 리콜은 0.5입니다.</p>{
 "metric_score": 0.5,
 "details": {
   "dicaprio-performance": {
     "metric_score": 1,
     "unrated_docs": [],
     "hits": [
       {
         "hit": {
           "_index": "movies",
           "_id": "doc1",
           "_score": 2.4826927
         },
         "rating": 1
       },
       {
         "hit": {
           "_index": "movies",
           "_id": "doc2",
           "_score": 2.0780432
         },
         "rating": 1
       }
     ],
     "metric_details": {
       "recall": {
         "relevant_docs_retrieved": 2,
         "relevant_docs": 2
       }
     }
   },
   "sad-movies": {
     "metric_score": 0,
     "unrated_docs": [],
     "hits": [],
     "metric_details": {
       "recall": {
         "relevant_docs_retrieved": 0,
         "relevant_docs": 2
       }
     }
   }
 },
 "failures": {}
}<p>쿼리의 모든 단어가 문서에 100% 포함되어야 한다고 요구하면 <strong>minimum_should_match</strong> 매개변수를 너무 엄격하게 적용해 관련성 있는 결과를 놓치고 있는 것일지도 모릅니다. 쿼리에서 단어가 하나만 발견되면 문서가 관련성이 있는 것으로 간주되도록 <strong>minimum_should_match</strong> 매개변수를 제거해 보겠습니다.</p>POST /movies/_rank_eval
{
 "requests": [
   {
     "id": "dicaprio-performance",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "DiCaprio performance"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc1",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc2",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc3",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc4",
         "rating": 0
       }
     ]
   },
   {
     "id": "sad-movies",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "sad movies that make you cry"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc5",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc6",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc7",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc8",
         "rating": 0
       }
     ]
   }
 ],
 "metric": {
   "recall": {
     "k": 10,
     "relevant_rating_threshold": 1
     }
 }
}<p>보시다시피, 두 쿼리 중 하나에서 <strong>minimum_should_match</strong> 매개 변수를 제거하면 두 쿼리 모두에서 평균 호출 횟수가 1이 됩니다.</p>{
  "metric_score": 1,
  "details": {
    "dicaprio-performance": {
      "metric_score": 1,
      "unrated_docs": [],
      "hits": [
        {
          "hit": {
            "_index": "movies",
            "_id": "doc1",
            "_score": 2.0661702
          },
          "rating": 1
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc3",
            "_score": 0.732218
          },
          "rating": 0
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc2",
            "_score": 0.6271719
          },
          "rating": 1
        }
      ],
      "metric_details": {
        "recall": {
          "relevant_docs_retrieved": 2,
          "relevant_docs": 2
        }
      }
    },
    "sad-movies": {
      "metric_score": 1,
      "unrated_docs": [],
      "hits": [
        {
          "hit": {
            "_index": "movies",
            "_id": "doc7",
            "_score": 2.1307156
          },
          "rating": 0
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc5",
            "_score": 1.3160692
          },
          "rating": 1
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc6",
            "_score": 1.190063
          },
          "rating": 1
        }
      ],
      "metric_details": {
        "recall": {
          "relevant_docs_retrieved": 2,
          "relevant_docs": 2
        }
      }
    }
  },
  "failures": {}
}<p>요약하면, minimum_should_match: 100% 절을 제거하면 두 쿼리 모두에 대해 완벽한 리콜을 얻을 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaf4f08a8a2915180/6a170df61949f76cbfe7aaba/24d055da4348c63827ba7046fe8cafb6f47cadd8-546x628.png" alt="" /><p>됐습니다! 성공하셨죠?</p><p>그렇게 어렵지 않아요!</p><p>리콜을 개선함으로써 더 폭넓은 결과를 확보할 수 있게 됩니다. 그러나 각 조정에는 상충되는 부분이 있습니다. 따라서 다양한 메트릭을 사용해 변경 사항을 평가하는 완전한 테스트 케이스를 정의해야 합니다.</p><p>판단 목록과 메트릭을 사용하면 변경 사항을 적용할 때 근거 데이터가 생기므로, 감에 의존해 판단하는 일을 피할 수 있습니다. 검증은 더 이상 수동적이고 반복적이지 않으며, 한 가지 사용 사례뿐만 아니라 여러 사용 사례에서 변경 사항을 테스트할 수 있습니다. 번역:또한 A/B 테스트를 통해 어떤 설정이 사용자와 비즈니스 사례에 가장 적합한지 실제 환경에서 검증할 수 있어, 기술적 메트릭에서 출발해 실제 메트릭으로 다시 연결되는 선순환을 완성할 수 있습니다.</p><h2>판단 목록 사용에 대한 최종 권장 사항</h2><p>판단 목록을 활용하는 것은 단순히 측정하는 것뿐만 아니라, 자신 있게 반복할 수 있는 프레임워크를 만드는 것이기도 합니다. 이를 위해 다음 권장 사항을 따르세요:</p><ol><li><p><strong>작은 시작이라도, 시작하세요</strong>. 각각 50개의 판단 목록이 있는 10,000개의 쿼리가 필요하지 않습니다. 비즈니스에 가장 중요한 쿼리를 5~10개 식별하고 결과의 상단에 표시할 문서를 정의하기만 하면 됩니다. 이것으로 이미 기반이 갖춰집니다. 일반적으로 상위 쿼리와 결과가 없는 쿼리부터 시작하는 것이 좋습니다. Precision과 같이 쉽게 구성할 수 있는 메트릭으로 테스트를 시작한 후, 복잡성을 높여 나갈 수 있습니다.</p></li><li><p><strong>사용자 검증을 통해 타당성을 검증하세요.</strong> 프로덕션 환경에서 A/B 테스트를 통해 수치를 보완하세요. 이렇게 하면 메트릭에서 좋아 보이던 변경 사항이 실제 영향을 발휘하고 있는지 알 수 있습니다.</p></li><li><p><strong>목록을 계속 유지하세요.</strong> 비즈니스 사례는 진화할 것이며 중요한 쿼리도 진화할 것입니다. 정기적으로 판단을 업데이트하여 새로운 필요를 반영하세요.</p></li><li><p><strong>워크플로의 일부로 만드세요.</strong> 판단 목록을 개발 파이프라인에 통합하세요. 각 구성 변경, 동의어 또는 텍스트 분석이 기본 목록에 대해 자동으로 검증되는지 확인하세요.</p></li><li><p><strong>기술 지식을 전략과 연결하세요.</strong> 정확도나 리콜과 같은 기술적 메트릭을 측정하는 데서 멈추지 마세요. 평가 결과를 활용하여 비즈니스 성과에 전달하세요.</p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/judgment-lists-search-query-relevance-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/judgment-lists-search-query-relevance-elasticsearch</guid>
    <category><![CDATA[정확도]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Jhon Guzmán]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcadfd2fb1cc95b4c/6a170df7acf0887798be9bd0/25478d0ffb228afd5d65d82312998ec1c299c565-700x490.png" length="0" type="image/png"/>
    <pubDate>Thu, 11 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elasticsearch에서 구조화된 문서에 대한 재귀 청크 구성하기]]></title>
    <description><![CDATA[최적의 구조화된 문서 색인을 위해 청크 크기, 구분자 그룹, 사용자 정의 구분자 목록을 사용하여 Elasticsearch에서 재귀적 청크를 구성하는 방법을 알아보세요.]]></description>
    <content:encoded><![CDATA[<p>8.16부터 사용자는 긴 문서를 의미론적 텍스트 필드로 수집할 때 사용되는 청킹 전략을 구성할 수 있습니다. 9.1 / 8.19 버전부터 정규식 목록을 사용하여 문서를 청크 처리하는 새로운 구성 가능한 재귀 청크 전략이 도입되었습니다. 청크의 목적은 긴 문서를 관련 콘텐츠를 캡슐화하는 섹션으로 분할하는 것입니다. 기존 전략은 단어/문장 단위로 텍스트를 분할하지만, 구조화된 형식으로 작성된 문서(예. 마크다운)에는 종종 일부 구분 문자열로 정의된 섹션 내에 관련 콘텐츠가 포함되어 있습니다(예 헤더). 이러한 유형의 문서에 대해 구조화된 문서의 형식을 활용하여 더 나은 청크를 만드는 재귀적 청크 전략을 소개합니다!</p><h2>재귀적 청킹이란 무엇인가요?</h2><p>재귀 청크는 패턴을 구분하는 제공된 섹션 목록을 반복하여 원하는 최대 청크 크기를 충족할 때까지 문서를 점진적으로 더 작은 세그먼트로 분할합니다.</p><h3>재귀 청킹은 어떻게 구성하나요?</h3><p>다음은 재귀 청킹을 위해 사용자가 설정할 수 있는 값입니다:</p><ul><li><p>(필수) <code>max_chunk_size</code>: 청크의 최대 단어 수입니다.</p></li><li><p>둘 중 하나입니다:</p><ul><li><p><code>separators</code>: 문서를 청크로 분할하는 데 사용할 정규식 문자열 패턴의 목록입니다.</p></li><li><p><code>separator_group</code>: 특정 유형의 문서에 사용하도록 Elastic에서 정의한 기본 구분 기호 목록에 매핑할 문자열입니다. 현재 <code>markdown</code> 및 <code>plaintext</code> 에서 사용할 수 있습니다.</p></li></ul></li></ul><h3>재귀 청크는 어떻게 작동하나요?</h3><p>입력 문서, <code>max_chunk_size</code> (단어로 측정), 구분 문자열 목록이 주어졌을 때 재귀 청킹을 수행하는 프로세스는 다음과 같습니다:</p><ol><li><p>입력 문서가 이미 최대 청크 크기 내에 있는 경우 전체 입력에 걸친 단일 청크를 반환합니다.</p></li><li><p>구분 기호의 발생 빈도에 따라 텍스트를 잠재적인 청크로 분할합니다. 각 잠재적 청크에 대해:</p><ol><li><p>잠재적 청크가 최대 청크 크기 이내인 경우 청크 목록에 추가하여 사용자에게 반환합니다.</p></li><li><p>그렇지 않으면 2단계부터 반복하여 잠재적 청크의 텍스트만 사용하고 목록의 다음 구분 기호를 사용하여 분할합니다. 더 이상 시도할 구분 기호가 남아 있지 않으면 문장 기반 청킹으로 돌아가세요.</p></li></ol></li></ol><h2>재귀 청킹 구성 예시</h2><p>청크 크기 외에도 재귀 청크의 주요 구성은 문서를 분할하는 데 사용할 구분 기호를 선택하는 것입니다. 어디서부터 시작해야 할지 잘 모르겠다면, Elasticsearch는 일반적인 사용 사례에 사용할 수 있는 몇 가지 기본 구분 기호 그룹을 제공합니다.</p><h3>구분 기호 그룹 활용</h3><p>구분 그룹을 사용하려면 청크 설정을 구성할 때 사용하려는 그룹의 이름을 입력하기만 하면 됩니다. 예를 들어</p>"chunking_settings": {
    "strategy": "recursive",
    "max_chunk_size": 25,
    "separator_group": "plaintext"
}<p>이렇게 하면 구분 기호 목록을 활용하는 재귀적 청크 전략이 제공됩니다 <code>["(?&lt;!\\n)\\n\\n(?!\\n)", "(?&lt;!\\n)\\n(?!\\n)")]</code>. 이 방법은 일반적인 일반 텍스트 애플리케이션에서 잘 작동하며, 두 줄로 분할한 다음 한 줄로 분할합니다.</p><p>또한 구분 기호 목록을 활용할 수 있는 구분 기호 그룹 <code>markdown</code> 을 제공합니다:</p>[
"\n# ",
       "\n## ",
       "\n### ",
       "\n#### ",
       "\n##### ",
       "\n###### ",
       "\n^(?!\\s*$).*\\n-{1,}\\n",
       "\n^(?!\\s*$).*\\n={1,}\\n"
]<p>이 구분 기호 목록은 일반적인 마크다운 사용 사례에 적합하며, 6개의 제목 수준과 섹션 구분 문자를 각각 분할할 수 있습니다.</p><p>리소스(추론 엔드포인트/시맨틱 텍스트 필드)를 만들 때 당시의 구분 기호 그룹에 해당하는 구분 기호 목록이 구성에 저장됩니다. 나중에 구분 기호 그룹이 업데이트되더라도 이미 생성된 리소스의 동작은 변경되지 않습니다.</p><h3>사용자 지정 구분 기호 목록 활용</h3><p>미리 정의된 구분 기호 그룹 중 하나가 사용 사례에 적합하지 않은 경우 필요에 맞는 사용자 지정 구분 기호 목록을 정의할 수 있습니다. 구분 기호 목록 내에 정규식을 입력할 수 있습니다. 다음은 사용자 지정 구분 기호로 구성된 청크 설정의 예입니다:</p>"chunking_settings": {
    "strategy": "recursive",
    "max_chunk_size": 25,
    "separators": ["\n\n", "\n", "&lt;my-custom-separator&gt;"]
}<p>위의 청크 전략은 2개의 줄 바꿈 문자, 1개의 줄 바꿈 문자, 마지막으로 문자열 <code>“&lt;my-custom-separator&gt;”</code> 로 분할됩니다.</p><h2>재귀 청크의 실제 사용 예시</h2><p>재귀 청크가 실제로 작동하는 예를 살펴보겠습니다. 이 예에서는 상위 두 개의 헤더 수준을 사용하여 마크다운 문서를 분할하는 사용자 지정 구분 기호 목록과 함께 다음 청크 설정을 사용합니다:</p>"chunking_settings": {
    "strategy": "recursive",
    "max_chunk_size": 25,
    "separators": ["\n# ", "\n## "]
}<p>청크가 없는 간단한 마크다운 문서를 살펴보겠습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdb5f41d1bd43ba50/6a17e831e9ea87c1d8a9c5f3/3a5507f4a1288065097231548e5b18e240508785-1302x1446.png" alt="청크되지 않은 마크다운 문서" /><p>이제 위에서 정의한 청킹 설정을 사용하여 문서를 청킹해 보겠습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfffda162c7b9c87a/6a17e83296142aefa8eb1b0b/a3313c4c40ff39b8dbcdd7c4878c723f088e6c1a-1600x1187.png" alt="Elasticsearch에서 문서 청크하기" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt96f65346a8e09e3a/6a17e834445de9157b4d015e/79a2921943191ea631df94c9d465818ec8d3e738-1600x1206.png" alt="두 번째 구분 기호로 분할하기 - Elasticsearch에서 문서 청크 분할하기" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt28381c8f85aedf07/6a17e836ec0f89801e5a6640/459e695cce7540267422396b9a62ff4ad35f61db-1600x1260.png" alt="Elasticsearch의 문장 기반 청크 처리 후 문서의 최종 청크" /><p>참고: 각 청크(청크 3 제외)의 끝에 있는 줄 바꿈은 강조 표시되지 않지만 실제 청크 경계 내에 포함됩니다.</p><h3>지금 바로 리커시브 청크를 시작하세요!</h3><p>이 기능을 활용하는 방법에 대한 자세한 내용은 청크 설정 구성에 대한 문서를 참조하세요.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/recursive-chunking-structured-documents-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/recursive-chunking-structured-documents-elasticsearch</guid>
    <category><![CDATA[기본]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <category><![CDATA[AI]]></category>
    <dc:creator><![CDATA[Daniel Rubinstein]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf442dc4941f37be7/6a17e838505ac3eaf8ad8b3d/591872e31880768ca927507654a621addc0d124d-1600x960.png" length="0" type="image/png"/>
    <pubDate>Tue, 11 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elasticsearch용 에이전트 AI 도구 개선 실험]]></title>
    <description><![CDATA[확장 가능한 RAG 최적화를 위해 선형 검색기, 하이브리드 검색, semantic_text를 결합하여 반복적인 실험을 통해 Elasticsearch의 AI 에이전트 워크플로우를 개선한 방법을 알아보세요.]]></description>
    <content:encoded><![CDATA[<p>요즘 다른 모든 사람들과 마찬가지로 Elastic도 Chat, 에이전트, RAG에 올인하고 있습니다. 검색 부서에서는 최근 에이전트 빌더와 도구 레지스트리를 개발 중이며, 모두 Elasticsearch에서 데이터와 '채팅'하는 것을 간단하게 만들기 위한 것입니다.</p><p>이러한 노력의 '큰 그림'에 <a href="https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">대해 자세히 알아보려면 Elasticsearch로 AI 에이전트 워크플로우 구축</a> <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">블로그 또는 첫 번째 Elastic 에이전트를 읽어보세요: 단일 쿼리에서 AI 기반 채팅까지에서</a> 보다 실용적인 입문서를 읽어보세요.</p><p>하지만 이 블로그에서는 채팅을 시작할 때 가장 먼저 일어나는 일 중 하나를 조금 더 자세히 살펴보고 최근 개선된 몇 가지 사항을 안내해드리려고 합니다.</p><h2>여기서 무슨 일이 일어나고 있나요?</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1331b1043612efe3/6a17f115505ac3dc41ad8c3c/25a24055a166d7d6ba81d80aa35cb97163662e23-1600x443.png" alt="" /><p>Elasticsearch 데이터와 채팅할 때 기본 AI 에이전트가 이 표준 플로우를 안내합니다:</p><ol><li><p>프롬프트를 확인합니다.</p></li><li><p>해당 프롬프트에 대한 답변이 포함되어 있을 가능성이 높은 인덱스를 식별합니다.</p></li><li><p>프롬프트에 따라 해당 인덱스에 대한 쿼리를 생성합니다.</p></li><li><p>해당 쿼리로 해당 인덱스를 검색합니다.</p></li><li><p>결과를 종합합니다.</p></li><li><p>결과가 프롬프트를 해결할 수 있나요? 그렇다면 응답하세요. 그렇지 않다면 반복하되 다른 것을 시도하세요.</p></li></ol><p>검색 증강 세대(RAG)에 불과하기 때문에 너무 새롭지 않을 것입니다. 예상대로 응답의 품질은 초기 검색 결과의 관련성에 따라 크게 달라집니다. 따라서 응답 품질을 개선하기 위해 노력하면서 3단계에서 생성하고 4단계에서 실행하는 쿼리에 매우 세심한 주의를 기울이고 있습니다. 그리고 흥미로운 패턴을 발견했습니다.</p><p>첫 번째 응답이 '나쁨'인 경우가 종종 있었는데, 이는 쿼리를 잘못 실행했기 때문이 아니었습니다. 쿼리할 <em>인덱스를 잘못 선택했기</em> 때문입니다. 3단계와 4단계는 보통 2단계가 문제가 되지 않았습니다.</p><h2>우리가 뭘 하고 있었나요?</h2><p>초기 구현은 간단했습니다. 저희는 <code>_cat/indices</code> 을 통해 사용 가능한 모든 인덱스를 나열한 다음, 이 인덱스 중 사용자의 메시지/질문/프롬프트에 가장 적합한 인덱스를 식별하도록 LLM에 요청하는 도구(index_explorer라고 함)를 구축했습니다. 이 <a href="https://github.com/elastic/kibana/blob/0cc78184957fcd12110dabae50353392ea937508/x-pack/platform/packages/shared/onechat/onechat-genai-utils/tools/index_explorer.ts#L98-L113">원본 구현은 여기에서</a> 확인할 수 있습니다.</p>You are an AI assistant for the Elasticsearch company.
based on a natural language query from the user, your task is to select up to ${limit} most relevant indices from a list of indices.

*The natural language query is:* ${nlQuery}

*List of indices:*
${indices.map((index) =&gt; `- ${index.index}`).join('\n')}

Based on those information, please return most relevant indices with your reasoning.
Remember, you should select at maximum ${limit} indices.<p>얼마나 잘 작동했나요? 확실하지 않았습니다! 잘 작동하지 <em>않는</em> 사례는 분명 있었지만, 현재 상태를 정량화하는 것이 첫 번째 과제였습니다.</p><h2>기준선 설정</h2><h3>데이터에서 시작됩니다.</h3><p>우리에게 필요했던 것은 사용자 프롬프트와 기존 인덱스 세트가 주어졌을 때 올바른 인덱스를 선택하는 도구의 효율성을 측정하기 위한 골든 데이터 세트였습니다. 그런 데이터 세트가 없었기 때문에 저희가 직접 생성했습니다.</p><p>인정합니다: 이것이 '모범 사례'는 아니라는 것을 알고 있습니다. 하지만 때로는 자전거를 타는 것보다 앞으로 나아가는 것이 더 나을 때도 있습니다. <a href="https://www.elastic.co/about/our-source-code#progress-perfection">진행, 심플한 완벽함</a>.</p><p><a href="https://gist.github.com/seanstory/a08db2e149897da656db3a1ca72e17ac">이 프롬프트를</a> 사용하여 여러 다른 도메인에 대한 시드 인덱스를 생성했습니다. 그런 다음 생성된 각 도메인에 대해<a href="https://gist.github.com/seanstory/a280a85d067e61bfeb5911bf2654e6e2"> 이 프롬프트를</a> 사용하여 몇 가지 인덱스를 더 생성했습니다(여기서 목표는 하드 네거티브와 분류하기 어려운 예시로 LLM에 혼란을 심어주는 것입니다). 다음으로, 생성된 각 인덱스와 그 설명을 수동으로 편집했습니다. 마지막으로 <a href="https://gist.github.com/seanstory/44291b666c05a383136f6e36bb9106fa">이 프롬프트를</a> 사용하여 테스트 쿼리를 생성했는데, 다음과 같은 샘플 데이터가 남았습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bd9cd78154195e3/6a17f117dbb4fff7b5fb57d2/9d96d87e286eddbc012402b1ecccd57419a99253-1600x782.png" alt="" /><p>와 같은 테스트 사례:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltadf30a0aeafd56ef/6a17f1192f4a5c160ffa89eb/4c2e9ad941d98d7e66033bbc08c9b8060ec19097-1600x797.png" alt="" /><h3>테스트 하네스 제작하기</h3><p>여기서부터의 과정은 매우 간단했습니다. 가능한 도구를 스크립트로 작성하세요:</p><ol><li><p>대상 Elasticsearch 클러스터로 클린 슬레이트를 설정하세요.</p></li><li><p>대상 데이터 세트에 정의된 모든 인덱스를 생성합니다.</p></li><li><p>각 테스트 시나리오에 대해 i<code>ndex_explorer</code> 도구를 실행합니다(편리하게도 <a href="https://www.elastic.co/docs/api/doc/kibana/operation/operation-post-agent-builder-tools-execute">도구 실행 API가</a> 있습니다).</p></li><li><p>결과 인덱스와 예상 인덱스를 비교하고 결과를 캡처합니다.</p></li><li><p>모든 테스트 시나리오를 완료한 후 결과를 표로 작성합니다.</p></li></ol><h3>설문조사에 따르면...</h3><p>초기 결과는 당연히 평범했습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt73367741359e258d/6a17f11a505ac39749ad8c40/9c10679bcd6291edfa2a9ba42e7dd922aa483f0b-1216x806.png" alt="" /><p>전반적으로 77.14% 올바른 인덱스를 식별하는 데 정확합니다. 그리고 이것은 모든 인덱스에 의미적으로 의미 있는 좋은 이름이 있는 '최상의 경우'의 시나리오입니다. PUT test2/_doc/foo {...}`를 해본 사람이라면 누구나 인덱스에 항상 의미 있는 이름이 있는 것은 아니라는 것을 알고 있습니다.</p><p>따라서 우리는 기준선을 가지고 있으며 개선의 여지가 많이 있음을 보여줍니다. 이제 과학이 필요한 시간입니다! 🧪</p><h2>실험</h2><h3>가설 1: 매핑이 도움이 될 것입니다.</h3><p>여기서 목표는 원래 프롬프트와 관련된 데이터를 포함할 인덱스를 식별하는 것입니다. 그리고 인덱스에 포함된 데이터를 가장 잘 설명하는 부분은 인덱스의 <em>매핑입니다</em>. 인덱스 콘텐츠의 샘플을 가져오지 않더라도 인덱스에 double 유형의 가격 필드가 있다는 것은 데이터가 판매할 상품을 나타낸다는 것을 의미합니다. 텍스트 유형의 작성자 필드는 일부 구조화되지 않은 언어 데이터를 의미합니다. 이 두 가지를 합치면 데이터가 책/이야기/시라는 것을 암시할 수 있습니다. 인덱스의 속성을 아는 것만으로도 많은 의미론적 단서를 얻을 수 있습니다. 그래서 로컬 브랜치에서 '.index_explorer`를 조정했습니다. 도구를 사용하여 인덱스의 전체 매핑(이름과 함께)을 LLM에 전송하여 결정을 내릴 수 있습니다. </p><p>결과(Kibana 로그에서 가져온):</p>[2025-09-05T11:01:21.552-05:00][ERROR][plugins.onechat] Error: Error calling connector: event: error
data: {"error":{"code":"request_entity_too_large","message":"Received a content too large status code for request from inference entity id [.rainbow-sprinkles-elastic] status [413]","type":"error"}}


    at createInferenceProviderError (errors.ts:90:10)
    at convertUpstreamError (convert_upstream_error.ts:39:38)
    at handle_connector_response.ts:26:33
    at Observable.init [as _subscribe] (/Users/seanstory/Desktop/Dev/kibana/node_modules/rxjs/src/internal/observable/throwError.ts:123:68)...<p>이 도구의 초기 개발자는 이러한 문제를 예상하고 있었습니다. 인덱스의 매핑은 정보를 얻을 수 있는 금광이지만, 상당히 장황한 JSON 블록이기도 합니다. 그리고 수많은 인덱스(평가 데이터 세트는 20개를 정의함)를 비교하는 현실적인 시나리오에서는 이러한 JSON 블롭이 합쳐집니다. 따라서 모든 옵션에 대한 인덱스 이름뿐만 아니라 각 옵션의 전체 매핑이 아닌 더 많은 컨텍스트를 LLM에 제공하여 결정에 도움을 주고자 합니다.</p><h3>가설 2: 절충안으로 '플랫화' 매핑(필드 목록) 사용</h3><p>우리는 인덱스 작성자가 의미론적으로 의미 있는 인덱스 이름을 사용한다는 가정에서 시작했습니다. 이 가정을 필드 이름으로도 확장하면 어떨까요? 이전 실험은 실패했는데, 그 이유는 JSON 매핑에 복잡한 메타데이터와 상용구가 많이 포함되어 있었기 때문입니다.</p>     "description_text": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          },
          "copy_to": [
            "description_semantic"
          ]
        },<p>예를 들어, 위의 블록은 236자이며 Elasticsearch 매핑에서 단 하나의 필드만 정의합니다. 반면 "description_text" 문자열은 16자에 불과합니다. 이는 문자 수가 거의 15배 증가한 것이지만, 해당 필드가 사용 가능한 데이터에 대해 의미하는 바를 설명하는 데 있어 의미 있는 의미 개선은 없습니다. 모든 인덱스에 대한 매핑을 가져오되, LLM으로 보내기 전에 필드 이름 목록으로만 '플랫화'하면 어떨까요?</p><p>저희도 사용해 보았습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta5eda7a79493ee81/6a17f11c9da390327fe46590/112c2f447c11f154b5082725cd49b51d0a3c8a65-1214x804.png" alt="" /><p>정말 멋지네요! 전반적으로 개선되었습니다. 하지만 더 잘할 수 있을까요?</p><h3>가설 3: 매핑 _meta의 설명</h3><p>추가 컨텍스트 없이 필드 이름만으로 그렇게 많은 점프가 발생했다면, 아마도 상당한 컨텍스트를 추가하는 것이 더 좋을 것입니다! 모든 인덱스에 반드시 설명을 첨부해야 하는 것은 아니지만, 매핑의 _meta 객체에 모든 종류의 인덱스 수준 메타데이터를 추가할 수 있습니다. 생성된 인덱스로 돌아가서 데이터 세트의 모든 인덱스에 대한 설명을 추가했습니다. 설명이 지나치게 길지 않다면 전체 매핑보다 적은 토큰을 사용하고 인덱스에 포함된 데이터에 대한 훨씬 더 나은 인사이트를 제공해야 합니다. 실험을 통해 이 가설을 검증했습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt61b85cf40e0e6357/6a17f11dfbc5f82809491bbe/32d2692ad4479d0e52d8ee723dcc5710a6ec90f3-1208x806.png" alt="" /><p>소폭의 개선으로 이제 &gt;90% 전반적으로 정확해졌습니다.</p><h3>가설 4: 합이 부분보다 큼</h3><p>필드 이름을 사용하면 결과가 향상되었습니다. 설명을 통해 결과가 향상되었습니다. 따라서 설명과 필드 이름을 <em>모두 </em>활용하면 더 나은 결과를 얻을 수 있겠죠?</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte6297c6aaf7db802/6a17f11e14d90c1bd779b6e6/114cbb408ff16b136251d2265416bd5270380fe5-1208x794.png" alt="" /><p>데이터는 "아니오"라고 응답했습니다(이전 실험에서 변경 사항 없음). 여기서 유력한 이론은 설명이 처음부터 인덱스 필드/매핑에서 생성되었기 때문에 이 두 컨텍스트 간에 서로 다른 정보가 충분하지 않아 결합할 때 '새로운' 것을 추가하는 데 도움이 되지 않는다는 것입니다. 또한 20개의 테스트 지수에 대해 전송하는 페이로드가 상당히 커지고 있습니다. 지금까지 우리가 따라온 사고방식은 확장할 수 없습니다. 사실, 지금까지의 실험 중 어떤 것도 수백, 수천 개의 인덱스가 있는 Elasticsearch 클러스터에서는 작동하지 않을 것이라고 믿을 만한 충분한 이유가 있습니다. 인덱스의 총 수가 증가함에 따라 LLM으로 전송되는 메시지 크기를 선형적으로 증가시키는 접근 방식은 일반화할 수 있는 전략이 아닐 수 있습니다.</p><p>우리에게 정말 필요한 것은 수많은 후보를 가장 관련성이 높은 옵션으로 좁히는 데 도움이 되는 접근 방식입니다....</p><p>여기에는 검색 문제가 있습니다.</p><h3>가설 5: 시맨틱 검색을 통한 선택</h3><p>인덱스 이름에 의미론적 의미가 있는 경우, 벡터로 저장하여 의미론적으로 검색할 수 있습니다.</p><p>인덱스의 필드 이름에 의미론적 의미가 있는 경우, 이를 벡터로 저장하고 의미론적으로 검색할 수 있습니다.</p><p>인덱스에 의미론적 의미가 있는 설명이 있는 경우, 이 역시 벡터로 저장하고 의미론적으로 검색할 수 있습니다.</p><p>오늘날 Elasticsearch 인덱스는 이러한 정보를 검색할 수 없지만(어쩌면 그렇게 해야 할지도 모릅니다!), 그 차이를 해결할 수 있는<a href="https://github.com/elastic/connectors/pull/3638"> 무언가를 함께 해킹하는</a> 것은 꽤나 사소한 일이었습니다. Elastic의 커넥터 프레임워크를 사용해 클러스터의 모든 인덱스에 대한 문서를 출력하는 커넥터를 구축했습니다. 출력 문서는 다음과 같은 형태가 됩니다:</p> doc = {
                "_id": index_name,
                "index_name": index_name,
			"meta_description”: description,
"field_descriptions" = field_descriptions,
                "mapping": json.dumps(mapping),  
                "source_cluster": self.es_client.configured_host,
            }<p>저는 이 문서들을 수동으로 매핑을 정의한 새 인덱스로 보냈습니다:</p>{
   "mappings": {
       "properties": {
           "semantic_content": {
               "type": "semantic_text"
           },
           "index_name": {
               "type": "text",
               "copy_to": "semantic_content"
           },
           "mapping": {
               "type": "keyword",
               "copy_to": "semantic_content"
           },
           "source_cluster": {
               "type": "keyword"
           },
           "meta_description": {
               "type": "text",
               "copy_to": "semantic_content"
           },
           "field_descriptions": {
               "type": "text",
               "copy_to": "semantic_content"
           }
       }
   }
}<p>이렇게 하면 의미론적 의미를 가진 다른 모든 필드가 청크업되어 색인되는 단일 semantic_content 필드가 생성됩니다. 이 인덱스를 검색하는 것은 사소한 일이 됩니다:</p>GET indexed-indices/_search
{
 "query": {
   "semantic": {
     "field": "semantic_content",
     "query": "$query"
   }
 }
}<p>수정된 <code>index_explorer</code> 도구는 이제 LLM에 요청할 필요 없이 주어진 쿼리에 대해 단일 임베딩을 요청하고 효율적인 벡터 검색 작업을 수행할 수 있으므로 <em>훨씬</em> 더 빨라졌습니다. 상위 히트를 선택한 지표로 삼은 결과 다음과 같은 결과를 얻었습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc27c302e6bef0b23/6a17f120577262d2f21bccdc/06ef5d78040d064d3444793f636d527d9e19a869-1214x800.png" alt="" /><p>이 접근 방식은 확장 가능합니다. 이 접근 방식은 효율적입니다. 하지만 이 접근 방식은 기준선보다 겨우 나은 수준입니다. 하지만 이는 놀라운 일이 아닙니다. 검색 접근 방식이 매우 순진하기 때문입니다. 뉘앙스가 없습니다. 인덱스의 이름과 설명이 인덱스에 포함된 임의의 필드 이름보다 더 많은 가중치를 가져야 한다는 인식이 없습니다. 동의어 일치보다 정확한 어휘 일치에 가중치를 부여하는 어포던스는 없습니다. 그러나 고도로 미묘한 쿼리를 작성하려면 현재 데이터에 대해 많은 것을 가정해야 합니다. 지금까지 인덱스와 필드 이름에 의미론적 의미가 있다는 큰 가정을 해 보았지만, 한 걸음 더 나아가서 <em>얼마나 많은</em> 의미를 가지고 있으며 서로 어떻게 연관되어 있는지 가정해 볼 필요가 있습니다. 이렇게 하지 않으면 최상의 일치 항목을 최고의 결과로 확실하게 식별할 수는 없지만, 상위 N개의 결과 중 어딘가에 최상의 일치 항목이 있다고 말할 수 있습니다. 우리는 의미론적 정보가 존재하는 맥락에서 의미론적 정보를 소비하고, 의미론적으로 구별되는 방식으로 자신을 표현할 수 있는 다른 개체와 비교하여 그 둘을 판단할 수 있는 무언가가 필요합니다. LLM처럼요.</p><h3>가설 6: 후보 세트 감소</h3><p>이 외에도 여러 가지 실험이 있었지만, 핵심적인 돌파구는 시맨틱 검색만으로 최적의 일치 항목을 고르려는 욕구를 버리고 대신 시맨틱 검색을 필터로 활용하여 LLM의 고려 대상에서 관련 없는 인덱스를 걸러내는 것이었습니다. <a href="https://gist.github.com/seanstory/d704443120e20f6c844db10e30066860">검색을</a> 위해 선형 검색기, 하이브리드 검색과 RRF, <code>semantic_text</code> 를 결합하여 상위 5개 일치하는 인덱스로 결과를 제한했습니다.</p><p>그런 다음 각 일치 항목에 대해 인덱스의 이름, 설명 및 필드 이름을 LLM용 메시지에 추가했습니다. 결과는 환상적이었습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7ac4cb8f7153fdf9/6a17f121af47b66d1dcde082/8fcabd78f591f90d6bc7c0e087d31317e4eef791-1206x804.png" alt="" /><p>역대 실험 중 가장 높은 정확도! 또한 이 접근 방식은 총 인덱스 수에 비례하여 메시지 크기가 증가하지 않기 때문에 훨씬 더 확장성이 뛰어납니다.</p><h2>결과</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8d66130d9fae6bea/6a17f123ddf97d7527910c19/04d630797213dbb8bf567da41d1cdd5c7b4586c9-1600x521.png" alt="" /><p>첫 번째 분명한 결과는 우리의 기준선을 개선할 <em>수</em> 있다는 것이었습니다. 지금 생각하면 당연해 보이지만 실험을 시작하기 전에는 <code>index_explorer</code> 도구를 완전히 버리고 검색 공간을 제한하기 위해 사용자의 명시적 설정에 의존해야 하는지에 대해 진지한 논의가 있었습니다. 여전히 실행 가능하고 유효한 옵션이지만, 이 연구는 이러한 사용자 입력을 사용할 수 없는 경우 인덱스 선택을 자동화하는 방향으로 나아갈 수 있는 유망한 경로가 있음을 보여줍니다.</p><p>다음으로 분명한 결과는 문제에 더 많은 설명 문자를 던지는 것만으로는 수익이 줄어든다는 것이었습니다. 이 연구 이전에는 <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-field-meta">필드 수준 메타데이터를</a> 저장하기 위해 Elasticsearch의 기능을 확장하는 데 투자해야 할지 고민하고 있었습니다. 현재 <code>meta</code> 값은 50자로 제한되어 있으며, 필드의 의미적 이해를 도출하기 위해서는 이 값을 늘려야 한다는 가정이 있었습니다. 이는 분명히 사실이 아니며, LLM은 필드 이름만으로 상당히 잘 작동하는 것 같습니다. 나중에 더 조사할 수 있지만 더 이상 시급하다고 생각하지 않습니다.</p><p>반대로, 이는 '검색 가능한' 인덱스 메타데이터의 중요성에 대한 명확한 증거가 되었습니다. 이 실험을 위해 저희는 인덱스 오브 인덱스를 해킹했습니다. 그러나 이것은 Elasticsearch에 직접 구축하거나, 관리할 API를 구축하거나, 최소한 관련 규칙을 수립하는 것을 검토할 수 있는 부분입니다. 여러 옵션을 검토하고 내부적으로 논의 중이니 계속 지켜봐 주시기 바랍니다.</p><p>마지막으로, 이러한 노력을 통해 시간을 들여 실험하고 데이터 기반 의사 결정을 내리는 것이 얼마나 가치 있는 일인지 확인했습니다. 실제로 에이전트 빌더 제품에 강력한 제품 내 평가 기능이 필요하다는 것을 재확인하는 데 도움이 되었습니다. 인덱스를 선택하는 도구만을 위한 전체 테스트 하네스를 구축해야 한다면, 고객은 반복적으로 조정할 때 사용자 지정 도구를 정성적으로 평가할 수 있는 방법이 반드시 필요합니다.</p><p>앞으로 무엇을 만들게 될지 기대가 되며, 여러분도 기대가 되시길 바랍니다!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-builder-experiments-performance</guid>
    <category><![CDATA[에이전틱 AI]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <category><![CDATA[하이브리드 검색]]></category>
    <dc:creator><![CDATA[Sean Story]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt68d11a4c7fd11d4c/6a17f1257b54f9b6598b39d4/42903c869e034674b30bb36013345aaa97f6608b-1184x864.png" length="0" type="image/png"/>
    <pubDate>Mon, 06 Oct 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[첫 번째 Elastic 에이전트: 단일 쿼리에서 AI 기반 채팅까지]]></title>
    <description><![CDATA[Elastic의 AI 에이전트 빌더를 사용해 전문화된 AI 에이전트를 생성하는 방법을 알아보세요. 이 블로그에서는 금융 AI 에이전트를 구축하는 방법을 소개합니다.]]></description>
    <content:encoded><![CDATA[<p>Elastic의 새로운 <a href="https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder">에이전트 빌더를</a> 사용하면 특정 비즈니스 도메인의 전문가 역할을 하는 전문화된 AI 에이전트를 생성할 수 있습니다. 이 기능은 단순한 대시보드와 검색창을 넘어 데이터를 수동적인 리소스에서 능동적인 대화 파트너로 탈바꿈시킵니다.</p><p>고객과의 미팅 전에 정보를 빠르게 파악해야 하는 재무 관리자가 있다고 상상해 보세요. 이제 수동으로 뉴스 피드를 검색하고 포트폴리오 대시보드를 상호 참조하는 대신 맞춤형 상담원에게 직접 질문할 수 있습니다. 이것이 바로 "채팅 우선" 접근 방식의 장점입니다. 관리자는 데이터에 직접 대화할 수 있는 라인을 통해 "ACME Corp의 최신 뉴스는 무엇이며 고객의 보유 자산에 어떤 영향을 미칩니까?" 같은 질문을 할 수 있습니다. 검색하면 몇 초 만에 종합적인 전문가 답변을 얻을 수 있습니다.</p><p>오늘날 금융 전문가를 구축하는 과정에서 데이터만큼이나 응용 분야도 다양합니다. 동일한 권한으로 위협을 찾아내는 사이버 보안 분석가, 장애를 진단하는 사이트 안정성 엔지니어, 캠페인을 최적화하는 마케팅 관리자를 만들 수 있습니다. 도메인에 관계없이 핵심 미션은 동일합니다. 데이터를 전문가와 대화할 수 있는 데이터로 전환하는 것입니다.</p><h2>0단계: 데이터 세트</h2><p>현재 저희 데이터 세트는 금융 계좌, 자산 현황, 뉴스 및 재무 보고서로 구성된 합성 금융 기반 데이터 세트입니다. 합성 데이터 세트이긴 하지만, 실제 금융 데이터 세트를 단순화한 버전을 재현한 것입니다.</p><p><code>financial_accounts</code>: 위험 프로필이 있는 고객 포트폴리오</p><p><code>financial_holdings</code>: 매수 내역이 있는 주식/ETF/채권 포지션</p><p><code>financial_asset_details</code>: 주식/ETF/채권에 대한 세부 정보</p><p><code>financial_news</code>: 감정 분석을 통해 AI가 생성한 시장 기사</p><p><code>financial_reports</code>: 기업 실적 및 애널리스트 노트</p><p>이 데이터 세트는 <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/your-first-elastic-agent/Your_First_Elastic_Agent.ipynb">여기에</a> 있는 첨부된 노트북을 따라 직접 로드할 수 있습니다.</p><h2>1단계: 기초 - ES|QL로서의 비즈니스 로직</h2><p>모든 AI 기술은 탄탄한 로직에서 시작됩니다. 재무 관리자 상담원에게 일반적인 질문에 답하는 방법을 가르쳐야 합니다: "시장 심리가 걱정됩니다. 어떤 고객이 나쁜 소식으로 가장 위험에 처해 있는지 보여 주시겠습니까?" 이 질문은 단순한 검색을 넘어서는 질문입니다. 이를 위해서는 시장 심리와 고객 포트폴리오의 상관관계를 파악해야 합니다.</p><p>부정적인 기사에 언급된 자산을 찾고, 해당 자산을 보유한 모든 고객을 식별하고, 해당 자산의 현재 시장 가치를 계산한 다음, 그 결과를 순위화하여 위험도가 가장 높은 자산의 우선순위를 정해야 합니다. 이러한 복잡한 다중 조인 분석은 고급 ES|QL 도구에 완벽한 작업입니다.</p><p>다음은 우리가 사용할 전체 쿼리입니다. 인상적으로 보이지만 개념은 간단합니다.</p><h2>분석: 조인 및 가드레일</h2><p>이 쿼리에는 상담원 빌더를 만드는 두 가지 중요한 개념이 작용하고 있습니다.</p><h3>1. 조회 조인</h3><p>수년 동안 Elasticsearch에서 가장 많이 요청된 기능 중 하나는 공통 키를 기반으로 서로 다른 인덱스의 데이터를 조인하는 기능이었습니다. 이제 ES|QL을 사용하면 <code>LOOKUP JOIN</code> 에서 가능합니다.</p><p>새 쿼리에서는 먼저 부정적인 뉴스를 자산 세부 정보에 연결한 다음, 해당 자산을 고객 보유 자산에 연결하고 마지막으로 고객의 계정 정보에 연결하는 세 개의 <code>LOOKUP JOIN</code> 연쇄를 수행합니다. 이렇게 하면 하나의 효율적인 쿼리에서 4개의 서로 다른 인덱스로부터 놀랍도록 풍부한 결과를 얻을 수 있습니다. 즉, 모든 데이터를 미리 하나의 거대한 인덱스로 비정규화할 필요 없이 서로 다른 데이터 집합을 결합하여 통찰력 있는 단일 답변을 만들 수 있습니다.</p><h3>2. LLM 가드레일로서의 매개변수</h3><p>쿼리가 <code>?time_duration</code> 을 사용하는 것을 알 수 있습니다. 이는 단순한 변수가 아니라 AI를 위한 보호 장치입니다. LLM(대규모 언어 모델)은 쿼리 생성에 탁월하지만, 데이터를 자유롭게 사용할 수 있도록 허용하면 비효율적이거나 심지어 잘못된 쿼리가 발생할 수도 있습니다.</p><p>매개변수화된 쿼리를 생성하여 전문가가 이미 정의한 테스트되고 효율적이며 올바른 비즈니스 로직 내에서 LLM이 작동하도록 강제합니다. 이는 개발자들이 수년 동안 검색 템플릿을 사용하여 애플리케이션에 쿼리 기능을 안전하게 노출해 온 방식과 유사합니다. 에이전트는 이번 주 "이번 주" 같은 사용자의 요청을 해석하여 <code>time_duration</code> 매개 변수를 채울 수 있지만, 반드시 쿼리 구조를 사용하여 답변을 얻어야 합니다. 이를 통해 유연성과 제어의 완벽한 균형을 이룰 수 있습니다.</p><p>궁극적으로 이 쿼리를 통해 데이터를 이해하는 전문가가 자신의 지식을 도구로 캡슐화할 수 있습니다. 그러면 다른 사람, 즉 AI 에이전트는 이 도구를 사용하여 근본적인 복잡성에 대해 아무것도 모른 채 단일 매개변수만 제공하면 상관관계가 있는 결과를 얻을 수 있습니다.</p><h2>2단계: 기술 - 쿼리를 재사용 가능한 도구로 전환하기</h2><p>ES|QL 쿼리는 <strong>도구로</strong> 등록하기 전까지는 텍스트에 불과합니다. 상담원 빌더에서 도구는 단순히 저장된 쿼리 그 이상의 의미로, AI 상담원이 이해하고 사용할 수 있는 "스킬(" )을 의미합니다. 마법 같은 것은 저희가 제공하는 <strong>자연어 설명에</strong> 있습니다. 이 설명은 사용자의 질문을 기본 쿼리 로직에 연결하는 다리 역할을 합니다. 방금 작성한 쿼리를 등록해 보겠습니다.</p><h3>UI 경로</h3><p>Kibana에서 도구를 만드는 것은 간단한 과정입니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte73e11c1d87593fa/6a17f2134202294dae29f6f2/a29c53a73b99af5972273c51218ea9004a9b0abb-1600x812.png" alt="Kibana에서 도구를 만드는 방법." /><p>1. <strong>상담원으로</strong>이동합니다.</p><ul><li><p><strong> 도구 </strong>또는 <strong>도구 관리를</strong> 클릭하고 <strong>새 도구</strong> 버튼을 클릭합니다.</p></li></ul><p>2. 다음 세부 정보를 입력하여 양식을 작성합니다:</p><ul><li><p><strong>도구 ID:</strong> <code>find_client_exposure_to_negative_news</code></p></li></ul><p>             i. 도구의 고유 ID입니다.</p><ul><li><p><strong>설명:</strong> "부정적인 뉴스에 노출된 고객 포트폴리오를 찾습니다. 이 도구는 최근 뉴스와 보고서에서 부정적인 감정을 검색하고 관련 자산을 식별한 후 해당 자산을 보유한 모든 고객을 찾아냅니다. 포지션의 현재 시장가 기준으로 정렬된 목록을 반환하여 잠재적 위험이 가장 높은 포지션을 강조 표시합니다."</p></li></ul><p>             i. LLM은 이를 읽고 이 도구가 작업에 적합한지 여부를 결정합니다.</p><ul><li><p><strong>레이블</strong>: <code>retrieval</code> 및 <code>risk-analysis</code></p></li></ul><p>         레이블은 여러 도구를 그룹화하는 데 사용됩니다.</p><ul><li><p><strong>구성으로 이동합니다:</strong> 1단계의 전체 ES|QL 쿼리 붙여넣기</p></li></ul><p>            i. 상담원이 사용할 검색은 다음과 같습니다.</p><p>3. <strong>쿼리에서 매개변수 유추를</strong> 클릭합니다. UI에서 <code>?time_duration</code> 을 자동으로 찾을 수 있습니다. 상담원(및 다른 사용자)이 목적을 이해하는 데 도움이 되도록 각각에 대한 간단한 설명을 추가하세요.</p><ul><li><p><code>time_duration</code>: 부정적인 뉴스를 다시 검색할 수 있는 기간입니다. 형식은 "X 시간" 기본값은 8760시간입니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7afbb0589c1828ad/6a17f2146864a44e7cb688a9/deb422d97863f78dbe08bfa2e3c708d1f75166ff-1600x938.png" alt="ESQL 쿼리를 사용하여 로직 및 필요한 매개변수를 포함하여 도구를 구성합니다. " /><p>4. 테스트해 보세요!</p><ul><li><p>저장 &amp; 테스트를 클릭합니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfd09afbef6e21a93/6a17f2162f4a5c73b1fa89fd/57e768b88327821e70bd616744822f98fa367362-732x136.png" alt="Kibana의 동일한 &amp; 테스트 버튼." /><ul><li><p>쿼리가 예상대로 작동하는지 테스트할 수 있는 새로운 플라이아웃이 표시됩니다.</p></li></ul><p>             i. <code>time_duration</code> 에서 원하는 범위를 입력합니다. 여기서는 "8760 시간"을 사용하고 있습니다.</p><ul><li><p>'제출'을 클릭하고 모든 것이 정상적으로 진행되면 JSON 응답이 표시됩니다. 예상대로 작동하는지 확인하려면 아래로 스크롤하여 <code>values</code> 개체를 확인합니다. 여기에서 실제 일치하는 문서가 반환됩니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt89bdc3f093363f2a/6a17f217be60861c9c00488a/7e0c5171a4f7ffdfc1830f1a05a9acb987870b75-1600x722.png" alt="제출을 클릭한 후 표시되는 JSON 응답입니다." /><p>5. 오른쪽 상단의 'X'를 클릭하여 테스트 플라이아웃을 닫습니다. 이제 새 도구가 목록에 표시되며 상담원에게 배정할 준비가 되었습니다.</p><h3>API 경로</h3><p>자동화를 선호하거나 프로그래밍 방식으로 도구를 관리해야 하는 개발자의 경우, 한 번의 API 호출로 동일한 결과를 얻을 수 있습니다. <code>POST</code> 요청을 <code>/api/agent_builder/tools</code> 엔드포인트에 도구의 정의와 함께 보내면 됩니다.</p>POST kbn://api/agent_builder/tools
{
  "id": "find_client_exposure_to_negative_news",
  "type": "esql",
  "description": "Finds client portfolio exposure to negative news. This tool scans recent news and reports for negative sentiment, identifies the associated asset, and finds all clients holding that asset. It returns a list sorted by the current market value of the position to highlight the highest potential risk.",
  "configuration": {
    "query": """
        FROM financial_news, financial_reports METADATA _index
        | WHERE sentiment == "negative"
        | WHERE coalesce(published_date, report_date) &gt;= NOW() - TO_TIMEDURATION(?time_duration)
        | RENAME primary_symbol AS symbol
        | LOOKUP JOIN financial_asset_details ON symbol
        | LOOKUP JOIN financial_holdings ON symbol
        | LOOKUP JOIN financial_accounts ON account_id
        | WHERE account_holder_name IS NOT NULL
        | EVAL position_current_value = quantity * current_price.price
        | RENAME title AS news_title
        | KEEP
            account_holder_name, symbol, asset_name, news_title,
            sentiment, position_current_value, quantity, current_price.price,
            published_date, report_date
        | SORT position_current_value DESC
        | LIMIT 50
      """,
    "params": {
      "time_duration": {
        "type": "keyword",
        "description": """The timeframe to search back for negative news. Format is "X hours" DEFAULT TO 8760 hours """
      }
    }
  },
  "tags": [
    "retrieval",
    "risk-analysis"
  ]
}<h2>3단계: 두뇌 - 사용자 지정 상담원 만들기</h2><p>재사용 가능한 스킬(도구)을 만들었습니다. 이제 실제로 사용할 페르소나, 즉 <strong>에이전트를</strong> 만들어야 합니다. 에이전트는 LLM, 액세스 권한을 부여한 특정 도구 세트, 그리고 가장 중요한 것은 에이전트의 성격, 규칙 및 목적을 정의하는 구성 요소 역할을 하는 <strong>사용자 지정 지침</strong> 세트의 조합입니다.</p><h3>프롬프트의 기술</h3><p>신뢰할 수 있는 전문 상담원을 만드는 데 있어 가장 중요한 부분은 바로 프롬프트입니다. 잘 만들어진 지침 세트는 일반 챗봇과 집중력 있는 전문 비서의 차이점입니다. 여기에서 가드레일을 설정하고, 출력을 정의하고, 에이전트에게 임무를 부여할 수 있습니다.</p><p><code>Financial Manager</code> 에이전트의 경우 다음 프롬프트를 사용합니다.</p>You are a specialized Data Intelligence Assistant for financial managers, designed to provide precise, data-driven insights from information stored in Elasticsearch.

**Your Core Mission:**
- Respond accurately and concisely to natural language queries from financial managers.
- Provide precise, objective, and actionable information derived solely from the Elasticsearch data at your disposal.
- Summarize key data points and trends based on user requests.

**Reasoning Framework:**
1.  **Understand:** Deconstruct the user's query to understand their core intent.
2.  **Plan:** Formulate a step-by-step plan to answer the question. If you are unsure about the data structure, use the available tools to explore the indices first.
3.  **Execute:** Use the available tools to execute your plan.
4.  **Synthesize:** Combine the information from all tool calls into a single, comprehensive, and easy-to-read answer.

**Key Directives and Constraints:**
- **If a user's request is ambiguous, ask clarifying questions before proceeding.**
- **DO NOT provide financial advice, recommendations, or predictions.** Your role is strictly informational and analytical.
- Stay strictly on topic with financial data queries.
- If you cannot answer a query, state that clearly and offer alternative ways you might help *within your data scope*.
- All numerical values should be formatted appropriately (e.g., currency, percentages).

**Output Format:**
- All responses must be formatted using **Markdown** for clarity.
- When presenting structured data, use Markdown tables, lists, or bolding.

**Start by greeting the financial manager and offering assistance.**<p>이 프롬프트가 효과적인 이유를 자세히 알아보세요:</p><ul><li><p><strong>이는 정교한 페르소나를 정의합니다: </strong>첫 번째 줄은 상담원을 "전문 데이터 인텔리전스 어시스턴트(" )로 즉시 설정하여 전문적이고 유능한 분위기를 조성합니다.</p></li><li><p><strong>추론 프레임워크를 제공합니다: </strong>상담원에게 "이해, 계획, 실행 및 종합," 표준 운영 절차를 제공하도록 지시합니다. 이를 통해 복잡한 다단계 질문을 처리하는 능력이 향상됩니다.</p></li><li><p><strong>대화형 대화를 촉진합니다: </strong>" 명확한 질문을" 하라는 지시는 상담원을 더욱 강력하게 만듭니다. 모호한 요청에 대한 잘못된 가정을 최소화하여 보다 정확한 답변으로 이어질 수 있습니다.</p></li></ul><h3>UI 경로</h3><p>1. <strong>상담원으로 이동</strong>합니다.</p><ul><li><p><strong> 도구 </strong>또는 <strong>도구 관리를</strong> 클릭하고 <strong>새 도구</strong> 버튼을 클릭합니다.</p></li></ul><p>2. 기본 세부 정보를 입력합니다:</p><ul><li><p><strong>상담원 ID:</strong> <code>financial_assistant</code>.</p></li><li><p><strong>지침을 따르세요: </strong>위의 프롬프트를 복사합니다.</p></li><li><p><strong>레이블</strong>: <code>Finance</code>.</p></li><li><p><strong>표시 이름:</strong> <code>Financial Assistant</code>.</p></li><li><p><strong>디스플레이 설명: </strong><code>An assistant for analyzing and understanding your financial data</code>.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8ac12cbd2b689dee/6a17f219dbb4ff262bfb57ef/18ea73f1cae620129c0afa0e7ba9e2a3390224a7-1600x1189.png" alt="재무 도우미 만들기 - 상담원 ID 필드 작성하기." /><p>3. 3. 상단으로 돌아가서 <strong>도구를</strong> 클릭합니다.</p><ul><li><p><code>find_client_exposure_to_negative_news</code> 도구 옆의 확인란을 선택합니다.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcd23556e556a76c5/6a17f21baf47b63a9fcde0a0/0c1e4ecbbd51d0dd10c6e861dbe9a9ccddeb35f6-1600x149.png" alt="" /><p>4. <strong>저장을</strong> 클릭합니다.</p><h3>API 경로</h3><p><code>/api/agent_builder/agents</code> 엔드포인트에 <code>POST</code> 요청을 통해 똑같은 에이전트를 만들 수 있습니다. 요청 본문에는 ID, 이름, 설명, 전체 지침, 상담원이 사용할 수 있는 도구 목록 등 모든 동일한 정보가 포함됩니다.</p>POST kbn://api/agent_builder/agents
    {
      "id": "financial_assistant",
      "name": "Financial Assistant",
      "description": "An assistant for analyzing and understanding your financial data",
      "labels": [
        "Finance"
      ],
      "avatar_color": "#16C5C0",
      "avatar_symbol": "💰",
      "configuration": {
        "instructions": """You are a specialized Data Intelligence Assistant for financial managers, designed to provide precise, data-driven insights from information stored in Elasticsearch.

**Your Core Mission:**
- Respond accurately and concisely to natural language queries from financial managers.
- Provide precise, objective, and actionable information derived solely from the Elasticsearch data at your disposal.
- Summarize key data points and trends based on user requests.

**Reasoning Framework:**
1.  **Understand:** Deconstruct the user's query to understand their core intent.
2.  **Plan:** Formulate a step-by-step plan to answer the question. If you are unsure about the data structure, use the available tools to explore the indices first.
3.  **Execute:** Use the available tools to execute your plan.
4.  **Synthesize:** Combine the information from all tool calls into a single, comprehensive, and easy-to-read answer.

**Key Directives and Constraints:**
- **If a user's request is ambiguous, ask clarifying questions before proceeding.**
- **DO NOT provide financial advice, recommendations, or predictions.** Your role is strictly informational and analytical.
- Stay strictly on topic with financial data queries.
- If you cannot answer a query, state that clearly and offer alternative ways you might help *within your data scope*.
- All numerical values should be formatted appropriately (e.g., currency, percentages).

**Output Format:**
- All responses must be formatted using **Markdown** for clarity.
- When presenting structured data, use Markdown tables, lists, or bolding.

**Start by greeting the financial manager and offering assistance.**
""",
        "tools": [
          {
            "tool_ids": [
              "platform.core.search",
              "platform.core.list_indices",
              "platform.core.get_index_mapping",
              "platform.core.get_document_by_id",
              "find_client_exposure_to_negative_news"
            ]
          }
        ]
      }
    }<h2>4단계: 보상 - 대화 나누기</h2><p>저희는 비즈니스 로직을 도구에 캡슐화하고 에이전트에서 사용할 수 있는 "브레인" 을 준비했습니다. 이제 이 모든 것이 한데 어우러질 때입니다. 이제 전문 상담원을 통해 데이터와 채팅을 시작할 수 있습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8826539b16e46f4/6a17f21d505ac35924ad8c5c/5414cb6b7c41365acb0356a8bfe1140751ffd8db-1600x1014.png" alt="재정 도우미를 생성한 후 Elastic 에이전트 빌더와 대화하기." /><h3>UI 경로</h3><ol><li><p>Kibana에서 <strong>에이전트로 </strong>이동합니다.</p></li><li><p>채팅 창의 오른쪽 하단에 있는 드롭다운을 사용하여 기본 <strong>Elastic AI 에이전트에서</strong> 새로 생성된 <strong>재무 지원 </strong>에이전트로 전환하세요.</p></li><li><p>상담원이 전문 도구를 사용할 수 있는 질문을 하세요:</p><ol><li><p><em>시장 심리가 걱정됩니다. 어떤 고객이 나쁜 소식으로 인해 가장 위험에 처해 있는지 보여주시겠어요?</em></p></li></ol></li></ol><p>잠시 후 상담원이 완벽한 형식의 완전한 답변을 반환합니다. LLM의 특성상 답변의 형식이 약간 다를 수 있지만 이번 실행에서는 상담원이 반환했습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta1e163fd7c4416bd/6a17f21f6864a4e35bb688ad/17b4ed43d279f9e53ee9fe3d482d0b2ec359a083-1600x1088.png" alt="부정적인 뉴스로 인해 가장 위험에 처한 고객을 위해 Elastic 에이전트 빌더가 금융 도우미로서 만든 응답입니다." /><h3>방금 무슨 일이 있었나요? 에이전트의 추론</h3><p>상담원은 "" 답을 알고 있었습니다. 작업에 가장 적합한 도구를 선택하는 데 중점을 둔 다단계 계획을 실행했습니다. 그 사고 과정을 살펴보세요:</p><ul><li><p><strong>의도를 확인했습니다:</strong> " 위험" 및 "부정적인 뉴스," 같은 질문의 키워드와 <code>find_client_exposure_to_negative_news</code> 도구의 설명이 일치했습니다.</p></li><li><p><strong>계획을 실행했습니다:</strong> 요청에서 기간을 추출하여 해당 전문 도구로 <strong>한 번만 호출합니다</strong>.</p></li><li><p><strong>작업 위임:</strong> 그런 다음 도구가 연쇄 조인, 값 계산 및 정렬과 같은 무거운 작업을 모두 수행했습니다.</p></li><li><p><strong>결과 종합:</strong> 마지막으로 에이전트는 프롬프트의 규칙에 따라 도구의 원시 데이터를 명확하고 사람이 읽을 수 있는 요약으로 포맷했습니다.</p></li></ul><p>생각을 확장하여 더 자세히 살펴보면 추측만 할 필요는 없습니다.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt93f6075be8495418/6a17f221af47b65eadcde0a4/6a4da9262d3f88c60bfd8f8bf9b67c3b84e961ba-1600x607.png" alt="재무 도우미가 부정적인 뉴스에 가장 많이 노출된 고객과 함께 찾은 50가지 문서입니다." /><h3>API 경로</h3><p>동일한 대화를 프로그래밍 방식으로 시작할 수 있습니다. 입력 질문을 <code>converse</code> API 엔드포인트로 보내면 되며, <code>financial_manager</code> 의 <code>agent_id</code> 을 지정해야 합니다.</p>POST kbn://api/agent_builder/converse
{
  "input": "Show me our largest positions affected by negative news",
  "agent_id": "financial_assistant"
}<h2>개발자용 API와 통합하기</h2><p>Kibana UI는 에이전트 구축과 관리를 위한 환상적이고 직관적인 환경을 제공하지만, 오늘 보신 모든 것을 프로그래밍 방식으로도 수행할 수 있습니다. 에이전트 빌더는 일련의 API를 기반으로 구축되었으므로 이 기능을 자체 애플리케이션, CI/CD 파이프라인 또는 자동화 스크립트에 직접 통합할 수 있습니다.</p><p>작업하게 될 세 가지 핵심 엔드포인트는 다음과 같습니다:</p><ul><li><p><strong><code>/api/agent_builder/tools</code></strong>: 상담원이 사용할 수 있는 재사용 가능한 스킬을 만들고, 나열하고, 관리하기 위한 엔드포인트입니다.</p></li><li><p><strong><code>/api/agent_builder/agents</code></strong>: 중요한 지침 및 도구 할당을 포함하여 상담원 페르소나를 정의하기 위한 엔드포인트입니다.</p></li><li><p><strong><code>/api/agent_builder/converse</code></strong>: 상담원과 상호작용하고, 대화를 시작하고, 답변을 얻기 위한 엔드포인트입니다.</p></li></ul><p>이 튜토리얼의 모든 단계를 수행하기 위해 이러한 API를 사용하는 방법에 대한 완전한 실습 과정을 보려면 여기 GitHub <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/your-first-elastic-agent/Your_First_Elastic_Agent.ipynb"></a> 리포지토리에서 함께 <strong>제공되는 Jupyter Notebook을 확인하세요.</strong></p><h2>결론: 빌드할 차례</h2><p>먼저 ES|QL 쿼리를 가져와 재사용 가능한 스킬로 변환하는 것으로 시작했습니다. 그런 다음 전문화된 AI 에이전트를 구축하여 명확한 미션과 규칙을 부여하고 해당 기술을 강화했습니다. 그 결과 복잡한 질문을 이해하고 다단계 분석을 실행하여 정확한 데이터 기반 답변을 제공할 수 있는 정교한 어시스턴트가 탄생했습니다.</p><p>이 워크플로는 Elastic의 새로운 <strong>에이전트 빌더의</strong> 핵심입니다. 기술 전문가가 아닌 사용자도 UI를 통해 에이전트를 만들 수 있을 만큼 간단하면서도 개발자가 API를 기반으로 맞춤형 AI 기반 애플리케이션을 구축할 수 있을 만큼 미묘한 차이가 있도록 설계되었습니다. 가장 중요한 것은 사용자가 정의한 전문 로직에 따라 LLM을 자신의 데이터에 안전하게 연결하고 데이터와 채팅할 수 있다는 점입니다.</p><h2>에이전트를 사용하여 데이터와 채팅할 준비가 되셨나요?</h2><p>배운 내용을 확고히 하는 가장 좋은 방법은 직접 손을 더럽히는 것입니다. <a href="https://www.elastic.co/training/elastic-ai-agents-mcp"><strong>무료 대화형 실습 워크숍에서</strong></a> 오늘 논의한 모든 내용을 직접 체험해 보세요. 전용 샌드박스 환경에서 이 전체 흐름과 그 이상을 체험할 수 있습니다.</p><p>향후 블로그에서는 <code>Financial Assistant</code> 에이전트와 상호 작용하는 독립형 애플리케이션을 사용하는 방법과 이 모든 것을 가능하게 하는 <strong>모델 컨텍스트 프로토콜(MCP)</strong> 에 대해 자세히 살펴보겠습니다. 그리고 별도의 블로그에서 에이전트 빌더의 에이전트2에이전트 또는 A2A 프로토콜 개발에 대한 지원에 대해 설명할 예정입니다.</p><p>앞으로도 계속 지켜봐 주시고, 행복한 구축이 되시길 바랍니다!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch</guid>
    <category><![CDATA[AI]]></category>
    <category><![CDATA[에이전틱 AI]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Jeff Vestal]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbe5e78eeb775d715/6a17f2230b0bed719ddd369a/ca853555eaa213f10f1db8c0ab0a2bbacee97b88-1456x816.png" length="0" type="image/png"/>
    <pubDate>Thu, 25 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Elasticsearch로 AI 에이전트 워크플로우 구축하기]]></title>
    <description><![CDATA[하이브리드 검색을 사용해 에이전트가 추론하고 행동하는 데 필요한 컨텍스트를 제공하는 AI 에이전트 워크플로우를 구축하기 위한 프레임워크를 제공하는 Elasticsearch의 새로운 AI 계층인 에이전트 빌더에 대해 알아보세요.]]></description>
    <content:encoded><![CDATA[<p>Elastic에서는 AI 어시스턴트, 고급 RAG, 벡터 데이터베이스 개선을 통해 LLM과 대화형 인터페이스에 컨텍스트를 제공해 왔습니다. 최근 AI 에이전트의 등장으로 관련 컨텍스트에 대한 필요성이 커지고 있으며, 영향력이 큰<strong> AI 에이전트에는 뛰어난 검색 기능이 필요하다는</strong> 사실을 알게 되었습니다. 그래서 Elasticsearch에서 데이터를 활용하는 AI 에이전트를 개발하는 데 도움이 되도록 설계된 새로운 기본 기능을 Elastic Stack에 구축했습니다. 이 여정의 진행 상황과 앞으로의 계획을 공유하고자 합니다.</p><h2>에이전트 빌더: 데이터 기반 AI 에이전트 구축을 위한 토대</h2><p>AI 에이전트의 약속은 간단합니다. 목표를 부여하면 작업을 완료한다는 것입니다. 하지만 개발자에게 현실은 복잡한 도전의 연속입니다. 첫째, 상담원은 환경에 대한 인식과 사용자 목표를 달성하기 위해 주어진 도구에 대한 인식이 뛰어나야 합니다. 그렇다면 다양한 기업 데이터에서 올바른 컨텍스트를 제공하는 것은 엄청난 과제입니다. 마지막으로, 이 모든 것은 계획, 실행, 학습할 수 있는 신뢰할 수 있는 추론 루프를 통해 조율되어야 합니다.</p><p>이를 해결하기 위해 개발자는 복잡하고 깨지기 쉬운 스택을 처음부터 새로 구축해야 합니다. 오늘날의 에이전트 아키텍처는 LLM, 벡터 데이터베이스, 메타데이터 저장소, 로깅 및 추적을 위한 별도의 시스템, 그리고 이 모든 것이 제대로 작동하는지 평가하는 방법 등 여러 가지 이질적인 조각들을 하나로 연결해야 합니다. 이는 복잡할 뿐만 아니라 비용이 많이 들고 오류가 발생하기 쉬우며 사용자가 요구하는 고품질의 신뢰할 수 있는 AI 시스템을 구축하기 어렵게 만듭니다.</p><p>그래서 저희는 더 간단하게 만들고자 합니다. 이를 위해, 저희의 접근 방식은 효과적인 컨텍스트 기반 에이전트의 필수 요소를 가져와 <strong>Elastic AI 에이전트 빌더라는</strong> 새로운 기능 세트를 통해 Elasticsearch의 핵심에 직접 통합하는 것입니다. 이 새로운 계층은 개방형 기본 요소 세트, 표준 기반 프로토콜, 데이터에 대한 안전한 액세스 등 Elasticsearch 기반 AI 에이전트를 생성하기 위한 모든 필수 구성 요소를 갖춘 프레임워크를 제공하므로 실제 데이터와 요구 사항에 맞는 에이전트 시스템을 구축할 수 있습니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2779dae5df010328/6a17e15eabe0f24f18dfe931/1ee1e73dd3f485ce86294d39490c98ce2a3d9925-1238x1072.png" alt="" /><p><strong>AI 경험 제공</strong>: 이것이 궁극적인 목표입니다. 검색 AI 플랫폼과 데이터를 기반으로 사용자 지정 채팅 인터페이스부터 LangChain과 같은 에이전트 프레임워크 또는 Salesforce와 같은 비즈니스 애플리케이션과의 통합에 이르기까지 모든 유형의 생성형 AI 애플리케이션을 구축할 수 있습니다.</p><p><strong>에이전트 제공 &amp; 도구</strong>: 플랫폼 위에 깔끔하고 단순한 추상화 계층을 노출합니다. 특정 요구 사항에 맞게 사용자 지정할 수 있는 상담원 및 도구와 직접 상호 작용합니다. 또한 강력한 API와 MCP 및 A2A와 같은 개방형 표준을 통해 플랫폼의 기능에 액세스할 수도 있습니다.</p><p><strong>검색 AI 플랫폼에서 사용 가능</strong>: 이 플랫폼은 구성 요소를 통합한 핵심 엔진입니다. 고급 벡터 데이터베이스, 에이전트 로직, 쿼리 구성, 보안 기능, 평가를 위한 추적 등 모든 것이 여기에 있으며, Elastic에서 관리하고 최적화합니다.</p><p><strong>데이터의 힘 활용하기</strong>: 훌륭한 상담원의 기본은 훌륭한 데이터입니다. Atlassian 플랫폼은 모든 엔터프라이즈 데이터에 대한 수집 또는 연합 액세스 기능으로 시작됩니다.</p><h2>플랫폼 내 에이전트 구축</h2><p>검색 AI 플랫폼에 통합된 에이전트 빌더는 에이전트 개발을 위한 완벽한 프레임워크를 제공합니다. 프로덕션급 AI 시스템 구축 및 배포의 중요한 측면을 해결하도록 설계된 5가지 핵심 요소를 기반으로 구축되었습니다. 에이전트가 목표를 정의하고, 도구가 기능을 제공하며, 개방형 표준이 상호 운용성을 보장하고, 평가가 투명성을 제공하고, 보안이 신뢰를 제공하는 방식을 세분화해 보겠습니다.</p><h3>상담원</h3><p>에이전트는 이 새로운 Elasticsearch 계층에서 가장 높은 수준의 빌딩 블록입니다. 에이전트는 달성할 목표, 실행에 사용할 수 있는 도구 세트 및 작동할 수 있는 데이터 소스를 정의합니다. 상담원은 대화형 상호작용에만 국한되지 않고 전체 워크플로, 작업 자동화 또는 사용자 대면 경험을 강화할 수 있습니다.</p><p>쿼리가 상담원에게 전달되면 구조화된 주기를 따릅니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt774ffd7df65bd01d/6a17e15f25daabd5cc08a17f/627ad1744b629bbe27359325702f40d97e40d1f4-704x852.png" alt="" /><ol><li><p>사용자의 입력과 목표 해석</p></li><li><p>실행에 적합한 도구와 인수를 선택합니다.</p></li><li><p>도구의 응답에 대한 이유</p></li><li><p>결과를 반환할지 아니면 추가 도구 호출을 계속할지 결정하세요.</p></li></ol><p>Elastic은 이 주기의 오케스트레이션, 컨텍스트 및 실행을 처리합니다. 개발자는 목표, 도구, 데이터 등 에이전트가 수행해야 할 <em>작업을</em> 정의하는 데 집중하고, 시스템은 추론과 워크플로우가 수행되는 <em>방식을</em> 관리합니다.</p><p><em>기본 에이전트</em></p><p>이 플랫폼을 기반으로 구축된 첫 번째 에이전트는 Kibana의 기본 대화형 에이전트로, 데이터와 즉시 상호 작용할 수 있는 기능을 제공합니다. 바로 사용할 수 있는 환경을 제공하는 동시에 완벽하게 확장 가능하며, 추가 구성 없이도 데이터와 즉시 상호 작용할 수 있습니다.</p><p>새로운 채팅 사용자 환경을 통해 또는 API를 통해 Kibana에서 직접 이 환경과 상호 작용할 수 있습니다.</p><p>API를 통해 기본 상담원을 쿼리하려면 한 번만 호출하면 됩니다:</p>POST kbn://api/agent_builder/converse
{
    "input": "what is our top portfolio account?"
}<p>대화가 상태 저장되므로 conversation_id 를 사용하여 상담원과 계속 대화하거나 전체 대화 기록을 검색할 수 있습니다:</p>POST kbn://api/agent_builder/converse
{
    "input": "What about the second top?",
    "conversation_id": "ec757c6c-c3ed-4a83-8e2c-756238f008bb"
}

## get the full conversation
GET kbn://api/agent_builder/conversations/ec757c6c-c3ed-4a83-8e2c-756238f008bb<p><em>맞춤형 상담원</em></p><p>개발자는 간단한 API를 통해 자신만의 사용자 지정 에이전트를 만들 수도 있습니다. 에이전트는 지침, 도구 및 데이터 액세스를 캡슐화하여 맞춤형 추론 엔진을 생성합니다.</p><p>사용자 지정 상담원을 만드는 것은 API 호출 한 번으로 간단합니다. 아래 샘플에서는 '구성' 필드에 지침이나 사용 가능한 도구 등 모든 주요 세부 정보가 들어 있는 예시를 보여 줍니다:</p>POST kbn://api/agent_builder/agents
{
  "id": "custom_agent",
  "name": "My Custom Agent",
  "description": "Description of the custom agent",
  "configuration": {
      "instructions": "You are a log expert specialising in ...",
      "tools": 
...
   }
}<p>에이전트가 생성되면 바로 쿼리할 수 있습니다:</p>POST kbn://api/agent_builder/converse
{
    "input": "What news about DIA?",
    "agent_id": "custom_agent"
}<p>이 접근 방식은 에이전트를 처음부터 구축해야 하는 복잡한 시스템에서 단순하고 선언적인 비즈니스 로직 단위로 전환하여 지능형 자동화를 더 빠르게 제공할 수 있도록 합니다.</p><p>전문 에이전트를 처음부터 구축하는 방법에 대해 자세히 알아보려면 자세한 단계별 가이드를 참조하세요: <a href="https://www.elastic.co/search-labs/blog/ai-agent-builder-elasticsearch">첫 번째 Elastic 에이전트: 단일 쿼리에서 AI 기반 채팅까지</a>.</p><h3>도구</h3><p>에이전트가 <em>무엇을</em> 달성할지 정의한다면 도구는 <em>어떻게</em> 달성할지 정의합니다.</p><p>도구는 에이전트가 정보를 실행 및 검색하거나 작업을 수행할 수 있도록 특정 Elastic 핵심 기능을 노출합니다. 도구에는 인덱스 가져오기 또는 매핑 가져오기와 같은 핵심 기능이나 자연어에서 ES|QL로의 고급 기능과 같은 고급 기능이 포함될 수 있습니다.</p><p>Elasticsearch는 일반적인 요구 사항에 최적화된 기본 도구 세트와 함께 제공됩니다. 하지만 진정한 유연성은 나만의 유연성을 만드는 데서 비롯됩니다. 도구를 정의함으로써 어떤 쿼리, 인덱스 및 필드를 ES|QL을 통해 에이전트에 노출할지 정확히 결정하여 속도, 정확성 및 보안을 정밀하게 제어할 수 있습니다.</p><p>새 도구를 등록하는 것도 API 호출 한 번으로 간단하게 할 수 있습니다. 특정 금융 자산에 대한 뉴스를 찾기 위해 <a href="https://www.elastic.co/search-labs/blog/esql-timeline-of-improvements">Elasticsearch 쿼리 언어(ES|QL)</a> 를 활용하는 도구를 만들 수 있습니다:</p>POST kbn://api/agent_builder/tools
{
  "id": "news_on_asset",
  "type": "esql",
  "description": "Find news and reports about a particular asset where ...",
  "configuration": {
    "query": "FROM financial_news, financial_reports | where MATCH(company_symbol, ?symbol) OR MATCH(entities, ?symbol) | limit 5",
    "params": {
      "symbol": {
        "type": "keyword",
        "description": "The asset symbol"
      }
    }
  ...
  }
...
}<p>등록한 후에는 새 도구를 사용자 지정 상담원에게 할당하여 선별된 기능을 추론하고 필요할 때마다 호출할 수 있도록 할 수 있습니다.</p><p>저희는 고객의 고유한 데이터 및 비즈니스 도메인에 기반하여 에이전트를 범용 에이전트에서 도메인별 전문가로 전환하는 ES|QL과 같이 고객의 특정 요구에 맞는 맞춤형 도구를 만들 수 있는 플랫폼을 제공합니다.</p><h3>개방형 표준 및 상호 운용성</h3><p>Elasticsearch 에이전트와 도구는 개방형 표준 API를 통해 노출되므로 에이전트 프레임워크의 광범위한 에코시스템 내에서 기본 블록으로 쉽게 통합할 수 있습니다. 우리의 접근 방식은 간단합니다: 블랙박스를 사용하지 않습니다. Elastic의 핵심 강점인 검색을 보완적인 기능 및 기타 에이전트 시스템과 결합하여 사용할 수 있기를 바랍니다.</p><p>이를 가능하게 하기 위해 저희는 API, 새로운 프로토콜, 개방형 표준을 통해 역량을 노출하고 있습니다.</p><p><em>모델 컨텍스트 프로토콜(MCP)</em></p><p><a href="https://www.elastic.co/search-labs/blog/model-context-protocol-elasticsearch">MCP(모델 컨텍스트 프로토콜)</a> 는 시스템 간 도구 연결을 위한 개방형 표준으로 빠르게 자리 잡고 있습니다. MCP를 지원함으로써 Elasticsearch는 대화형 AI를 데이터베이스, 인덱스 및 외부 API에 연결할 수 있습니다. Elastic Stack에 내장된 원격 MCP 서버를 통해 모든 MCP 호환 클라이언트는 Elastic의 도구에 액세스하고 이를 대규모 에이전트 워크플로우의 빌딩 블록으로 사용할 수 있습니다.</p><p>이것은 일방통행이 아닙니다. 또한 외부 MCP 서버에서 도구를 가져와서 Elasticsearch 내에서 사용할 수 있게 할 수도 있습니다. 곧 MCP 서버는 거의 모든 용도로 사용할 수 있게 될 것이며, 우리가 직접 만드는 것보다 훨씬 더 포괄적인 서버가 될 것입니다. Elastic은 대규모 검색 및 검색 기능을 제공하며, 이를 다른 플랫폼의 전문 기능과 결합하여 효과적인 에이전트를 구축할 수 있습니다.</p><p><em>에이전트 간(A2A)</em></p><p>또한 에이전트 간(A2A) 지원도 준비 중입니다. MCP가 툴을 연결하는 것이라면 A2A는 에이전트를 연결하는 것이 핵심입니다. A2A 서버를 사용하면 구축한 Elastic 에이전트가 다른 시스템의 에이전트와 직접 대화하여 컨텍스트를 공유하고, 작업을 위임하고, 워크플로우를 조정할 수 있습니다.</p><p>추론 계층에서의 상호 운용성이라고 생각하면 됩니다. Elastic 에이전트가 검색 및 검색을 처리한 다음 전문 지원팀이나 IT 에이전트에게 작업을 넘겨주고 결과를 원활하게 돌려받을 수 있습니다. 그 결과 각자가 가장 잘하는 일을 하는 협력 에이전트로 구성된 생태계가 탄생했습니다.</p><p>궁극적으로 MCP와 A2A를 채택함으로써, 더 광범위한 에이전트 에코시스템 전반에 걸쳐 개방형 통합을 보장하는 일류 시민으로서 Elasticsearch의 역할에 대한 우리의 약속을 강화할 수 있게 되었습니다.</p><h3>추적 및 평가</h3><p>검색이 상담원과 통합됨에 따라 효과적인 평가라는 과제가 중요해졌습니다. 실제 기업 환경에서 자신 있게 에이전트를 배포하려면 정확할 뿐만 아니라 효율적이고 신뢰할 수 있다는 확신이 있어야 합니다. 성능을 측정하고, 잘못된 응답을 진단하거나, 기준선을 개선하려면 어떻게 해야 하나요? 모든 것은 가시성에서 시작됩니다.</p><p>이것이 바로 처음부터 투명성을 위해 상담원 API를 설계한 이유입니다. 이 간단한 상담원 상호 작용을 생각해 보세요:</p>POST kbn://api/agent_builder/converse
{
    "input": "what is our top portfolio account?"
}<p>응답에는 최종 답변뿐만 아니라 상담원이 선택한 도구, 사용한 매개변수 및 각 단계의 결과를 자세히 설명하는 전체 실행 추적이 포함됩니다.</p>{
  "conversation_id": "db5c0c8b-12bf-4928-a57e-d99129ad2fea",
  "steps": [
    {
      "type": "tool_call",
      "tool_call_id": "tooluse_Nfqr3mwtR92HTRIsTcGXZQ",
      "tool_id": ".index_explorer",
      "params": {
        "query": "indices containing portfolio data"
      },
      "results": [...]
    }
    // ... more steps ...
  ],
  "response": {
    "message": "Based on the information I've gathered...."
  }
}<p>포괄적인 추적과 로깅은 지속적인 개선 루프에 필수적이며, 곧 이러한 에이전트 추적을 Elasticsearch에 직접 저장하고 볼 수 있게 됩니다. 더 좋은 점은 이러한 추적이 OpenTelemetry 프로토콜을 기반으로 구축되어 표준화되고 원하는 통합 가시성 플랫폼과 통합할 수 있도록 이식성이 보장된다는 것입니다.</p><p>이러한 수준의 세부 사항은 진정한 지속적인 개선 루프의 토대입니다. 포괄적인 테스트 제품군을 구축하고, 실패를 디버그하고, 실패 모드를 식별하여 회귀를 방지하고, 성공 패턴을 캡처하여 성능을 미세 조정할 수 있습니다. 궁극적으로 이러한 데이터 중심 접근 방식은 유망한 프로토타입을 생산 등급의 신뢰할 수 있는 AI 시스템으로 전환하는 데 핵심적인 역할을 합니다.</p><h3>보안</h3><p>에이전트와 툴의 기능이 향상됨에 따라 보안은 선택 사항이 아니라 기본이 되었습니다. API를 노출하고, 작업을 자동화하고, 워크플로우를 자동화하려면 엔터프라이즈 시스템을 신뢰할 수 있어야 합니다. 특히 상담원이 더 많은 워크플로를 자동화하기 시작하면서 이러한 워크플로를 보호하고 기업의 요구 사항을 충족할 수 있는 기능이 필수적입니다.</p><p>무엇보다도 이 기능은 API 호출을 위한 <a href="https://www.elastic.co/search-labs/blog/rag-and-rbac-integration">역할 기반 액세스 제어(RBAC)</a> 와 API 키 관리를 포함해 현재 Elastic에서 이미 사용 가능한 제어 기능을 그대로 계승합니다. 또한 MCP와 같은 새로운 프로토콜에도 동일한 제어 기능을 확장하고 있습니다. 즉, OAuth와 같은 표준을 지원할 뿐만 아니라 사용자 지정 인증 메커니즘을 연결할 수 있습니다.</p><p>저희의 목표는 조직이 요구하는 보안, 규정 준수 및 거버넌스 수준을 유지하면서 에이전트와 도구를 유연하게 실험할 수 있도록 하는 것입니다.</p><h2>다음 단계</h2><p>단순히 기능만 추가하는 것이 아니라 에이전트 컨텍스트 엔지니어링을 위해 Elasticsearch를 확장하고 있습니다. 앞으로도 이러한 원칙에 따라 발전해 나갈 계획입니다:</p><p>1. 오픈 소스 &amp; 표준에 대한 약속</p><p>오픈 소스 및 개방형 표준에 대한 당사의 노력은 이러한 기능이 외부 에이전트 프레임워크와 상호 운용성을 유지하도록 보장합니다. 데이터와 워크플로우를 항상 제어하면서 에코시스템 전반에서 에이전트를 연결, 확장 및 구성할 수 있습니다.</p><p>2. 컨텍스트의 가치</p><p>AI 에이전트의 가장 큰 자산은 컨텍스트입니다. 상담원이 검색 및 워크플로 작업을 수행할 때 컨텍스트를 관리하는 것은 어려운 작업일 수 있습니다. 저희는 Elastic의 핵심 강점을 활용하여 컨텍스트 엔지니어링을 해결함으로써 상담원이 항상 가장 관련성 높은 정보를 사용할 수 있도록 보장하고 있습니다.</p><p>3. 에이전트 데이터 스트림에 집중</p><p>앞으로 상담원은 상담원의 출력물(생성된 문서, 보고서, 시각화)과 상담원의 실행 추적(사고, 도구 호출, 메모리/컨텍스트)을 포함하여 점점 더 큰 데이터 소스가 될 것입니다. Elastic은 이러한 유형의 데이터를 처리하는 데 매우 적합하며, 이러한 데이터를 사용하여 분석, 평가 및 자동화된 개선 작업을 수행하는 것과 관련된 연구를 진행하고 있습니다.</p><p>4. 설계를 통한 보안 및 안전</p><p>AI 에이전트는 완전히 새로운 보안 및 안전 문제를 야기합니다. Elastic은 항상 보안 솔루션의 리더로서 엔터프라이즈급 가드레일, 액세스 제어, "제로 트러스트" 원칙을 지속적으로 구축해 왔습니다.</p><p>5. 플랫폼에 내장</p><p>AI 에이전트를 구축하기 위한 기능은 Elasticsearch 플랫폼에 내장되어 있습니다. 즉, 추적, 평가, 시각화 및 분석과 같은 플랫폼 수준의 기능을 모두 상담원에게 적용할 수 있습니다. 에이전트 실행을 기반으로 대시보드를 개발하려는 경우 - 이 기능이 기본으로 제공됩니다. 감정 분석을 사용하여 AI 상담원의 성과를 평가하고 싶다면 이 플랫폼을 통해 가능합니다. 이를 통해 AI 경험을 중심으로 완전한 라이프사이클을 구축할 수 있습니다.</p><p>Elastic의 목표는 완전히 통합되고 확장 가능하며 데이터에 기반한 대화형 AI와 자동화된 워크플로우를 구축할 수 있는 인터페이스를 제공하는 것입니다. 자세한 기술적 세부 사항과 진행 상황은 곧 공유될 예정입니다.</p><p>상담원 빌더는 현재 비공개 미리 보기로 제공됩니다. 액세스 권한을 요청하려면 <a href="https://www.elastic.co/contact?pg=global&amp;plcmt=nav&amp;cta=205352">당사에 문의</a> 하세요. 질문이나 피드백이 있으신가요? <a href="https://elasticstack.slack.com/archives/C09GRHEQ4AG"><strong>Slack 워크스페이스</strong></a> 또는 <a href="https://discuss.elastic.co/c/search/84"><strong>토론 포럼에서</strong></a> 개발자 커뮤니티와 소통하세요.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/ai-agentic-workflows-elastic-ai-agent-builder</guid>
    <category><![CDATA[AI]]></category>
    <category><![CDATA[에이전틱 AI]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Anish Mathur,Dana Juratoni]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt16a3d8736bf086e0/6a17e1616864a45410b686c7/71876470119e02a45bcbfcbf27a3e110328bbd14-1020x654.png" length="0" type="image/png"/>
    <pubDate>Tue, 23 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[벡터 검색 필터링: 관련성 유지]]></title>
    <description><![CDATA[쿼리와 가장 유사한 결과를 찾기 위해 벡터 검색을 수행하는 것만으로는 충분하지 않습니다. 검색 결과의 범위를 좁히기 위해 필터링이 필요한 경우가 많습니다. 이 문서에서는 Elasticsearch와 Apache Lucene에서 벡터 검색을 위한 필터링이 어떻게 작동하는지 설명합니다.]]></description>
    <content:encoded><![CDATA[<p>벡터 검색만으로는 관련 검색 결과를 찾을 수 없습니다. 검색 결과의 범위를 좁히고 관련 없는 결과를 걸러내는 데 도움이 되는 필터링 기준을 사용하는 것은 매우 일반적입니다.</p><p>벡터 검색에서 필터링이 작동하는 방식을 이해하면 성능과 회상률의 균형을 맞추는 데 도움이 될 뿐만 아니라 필터링 사용 시 벡터 검색의 성능을 높이는 데 사용되는 몇 가지 최적화를 알아볼 수 있습니다.</p><h2>왜 필터링할까요?</h2><p>벡터 검색은 대규모 데이터 세트에서 관련 정보를 찾는 방법을 혁신적으로 개선하여 검색어와 의미적으로 유사한 항목을 발견할 수 있게 해줍니다.</p><p>하지만 단순히 비슷한 아이템을 찾는 것만으로는 충분하지 않습니다. 특정 기준이나 속성에 따라 검색 결과의 범위를 좁혀야 하는 경우가 많습니다.</p><p>이커머스 스토어에서 제품을 검색하고 있다고 상상해 보세요. 순수한 벡터 검색은 시각적으로 유사한 상품을 보여줄 수 있지만 가격대, 브랜드, 재고 여부 또는 고객 평점을 기준으로 필터링할 수도 있습니다. 필터링이 없으면 유사한 상품이 너무 많이 표시되어 원하는 상품을 정확히 찾기 어렵습니다.</p><p>필터링을 통해 검색 결과를 정밀하게 제어할 수 있으므로 검색된 항목이 의미적으로 일치할 뿐만 아니라 필요한 모든 요건을 충족하는지 확인할 수 있습니다. 이를 통해 훨씬 더 정확하고 효율적이며 사용자 친화적인 검색 환경을 제공합니다.</p><p>다양한 데이터 유형에 걸쳐 효과적인 필터링을 사용하는 것이 다른 벡터 데이터베이스와의 주요 차이점 중 하나인 Elasticsearch와 Apache Lucene의 장점입니다.</p><h2>정확한 벡터 검색을 위한 필터링</h2><p>정확한 벡터 검색을 수행하는 방법에는 크게 두 가지가 있습니다:</p><ul><li><p>dense_vector 필드에 <code>flat</code> 인덱스 유형을 사용합니다. 따라서 <code>knn</code> 검색은 대략적인 검색이 아닌 정확한 검색을 사용합니다.</p></li><li><p>벡터 함수를 사용하여 점수를 계산하는 <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-script-score-query#vector-functions">스크립트_점수 쿼리를</a> 사용합니다. 모든 인덱스 유형에 사용할 수 있습니다.</p></li></ul><p>정확한 벡터 검색을 실행할 때는 모든 벡터가 쿼리와 비교됩니다. 이 시나리오에서는 필터를 통과한 벡터만 비교하면 되므로 필터링이 성능에 도움이 됩니다.</p><p>어쨌든 모든 벡터가 고려되므로 결과 품질에는 영향을 미치지 않습니다. 흥미롭지 않은 결과를 미리 필터링하여 작업 횟수를 줄일 수 있습니다.</p><p>적용된 필터로 인해 문서 수가 적은 경우 대략적인 검색 대신 정확한 검색을 실행하는 것이 더 효율적일 수 있으므로 이는 매우 중요합니다.</p><p>필터를 통과하는 문서가 1만 개 미만인 경우 정확한 검색을 사용하는 것이 좋습니다. <a href="https://www.elastic.co/search-labs/blog/better-binary-quantization-lucene-elasticsearch">BBQ</a> 인덱스가 비교에 훨씬 빠르므로 기준 인덱스가 10만 개 미만일 때는 정확한 검색을 사용하는 것이 좋습니다. 자세한 내용은 <a href="https://www.elastic.co/search-labs/blog/knn-exact-vs-approximate-search">이 블로그 게시물을</a> 확인하세요.</p><p>필터가 항상 매우 제한적인 경우에는 HNSW 기반 인덱스 유형 대신 <code>flat</code> 인덱스 유형을 사용하여 대략적인 검색 대신 정확한 검색에 초점을 맞춘 인덱싱을 고려할 수 있습니다. 자세한 내용은 <a href="https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/dense-vector#dense-vector-params">index_options의 속성을</a> 참조하세요.</p><h2>대략적인 벡터 검색을 위한 필터링</h2><p>근사 벡터 검색을 실행할 때는 결과 정확도와 성능을 맞바꿉니다. HNSW와 같은 벡터 검색 데이터 구조는 수백만 개의 벡터에서 대략적인 가장 가까운 이웃을 효율적으로 검색합니다. 계산 비용이 많이 드는 벡터 비교를 최소한으로 수행하여 가장 유사한 벡터를 검색하는 데 중점을 둡니다.</p><p>즉, 다른 필터링 속성은 벡터 데이터의 일부가 아닙니다. 용어 사전, 게시 목록, 문서 값 등 데이터 유형마다 이를 찾고 필터링하는 데 효율적인 자체 인덱싱 구조가 있습니다.</p><p>이러한 데이터 구조가 벡터 검색 메커니즘과 분리되어 있다면 벡터 검색에 필터링을 적용하려면 어떻게 해야 할까요? 벡터 검색 후 필터를 적용하거나(사후 필터링) 벡터 검색 전에 필터를 적용하는(사전 필터링) 두 가지 옵션이 있습니다.</p><p>각 옵션에는 장단점이 있습니다. 더 자세히 알아봅시다!</p><h3>사후 필터링</h3><p>사후 필터링은 벡터 검색이 완료된 후 필터를 적용합니다. 즉, 필터는 가장 유사한 벡터 결과 상위 k개를 찾은 후에 적용됩니다.</p><p>물론 결과에 필터를 적용한 후 잠재적으로 k보다 적은 결과를 얻을 수 있습니다. 물론 벡터 검색에서 더 많은 결과를 검색할 수 있지만(k 값이 높을수록) 필터를 적용한 후에도 k 이상의 결과를 얻을 수 있을지는 확신할 수 없습니다.</p><p>사후 필터링의 장점은 벡터 검색의 런타임 동작을 변경하지 않는다는 점입니다. 벡터 검색은 필터링을 인식하지 못합니다. 하지만 검색되는 최종 결과 수는 변경됩니다.</p><p>다음은 <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-knn-query">knn 쿼리를</a> 사용한 사후 필터링의 예입니다. 필터링 절이 knn 쿼리와 분리되어 있는지 확인합니다:</p>{
  "query": {
    "bool": {
      "must": {
        "knn": {
          "field": "image-vector",
          "query_vector": [54, 10, -2],
          "k": 5,
          "num_candidates": 50
        }
      },
      "filter": {
        "term": {
          "file-type": "png"
        }
      }
    }
  }
}<p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/filter-search-results#post-filter">포스트 필터를</a> 사용하여 KNN 검색에 포스트 필터링도 사용할 수 있습니다:</p>{
  "knn": {
    "field": "image-vector",
    "query_vector": [54, 10, 2],
    "k": 5,
    "num_candidates": 50
  },
  "post_filter": {
    "term": {
      "file-type": "png"
    }
  }
}<p>knn 검색에 명시적인 사후 필터 섹션을 사용해야 한다는 점에 유의하세요. 사후 필터를 사용하지 않는 경우 knn 검색은 <a href="https://www.elastic.co/docs/solutions/search/vector/knn#_combine_approximate_knn_with_other_features">사후 필터를 수행하는 대신 가장</a> 가까운 이웃 검색 결과를 다른 쿼리 또는 필터와 결합합니다.</p><h3>사전 필터링</h3><p>벡터 검색 전에 필터를 적용하면 먼저 필터를 충족하는 문서를 검색한 다음 해당 정보를 벡터 검색에 전달합니다.</p><p>Lucene은 <a href="https://github.com/apache/lucene/blob/7a60d7ce92392181e137361336e5196bd486cdd9/lucene/core/src/java/org/apache/lucene/util/BitSet.java">비트셋을</a> 사용하여 필터 조건을 충족하는 문서를 효율적으로 저장합니다. 그런 다음 벡터 검색은 조건을 충족하는 문서를 고려하여 HNSW 그래프를 탐색합니다. 결과에 후보를 추가하기 전에 유효한 문서의 비트 집합에 포함되어 있는지 확인합니다.</p><p>그러나 유효한 문서가 아니더라도 후보를 탐색하고 쿼리와 비교해야 합니다. HNSW의 효과는 그래프에서 벡터 간의 연결에 따라 달라지는데, 한 후보 탐색을 중단하면 이웃 후보도 건너뛸 수 있습니다.</p><p>주유소에 가기 위해 운전한다고 생각하세요. 주유소가 없는 도로를 버리면 목적지까지 갈 수 없을 가능성이 높습니다. 다른 길은 내가 원하는 길이 아닐 수도 있지만 목적지까지 <em>연결해</em> 줍니다. HNSW 그래프의 벡터도 마찬가지입니다!</p><p>따라서 사전 필터링을 적용하는 것이 필터를 적용하지 않는 것보다 성능이 떨어집니다. 검색에서 방문하는 <em>모든</em> 벡터에 대한 작업을 수행해야 하며 필터와 일치하지 않는 벡터는 버려야 합니다. 최고의 결과를 얻기 위해 더 많은 노력을 기울이고 더 많은 시간을 투자하고 있습니다.</p><p>다음은 Elasticsearch 쿼리 DSL에서 사전 필터링의 예입니다. 필터링 절이 이제 knn 섹션의 일부가 되었는지 확인합니다:</p>{
  "knn": {
    "field": "image-vector",
    "query_vector": [54, 10, -2],
    "k": 5,
    "num_candidates": 50,
    "filter": {
      "term": {
        "file-type": "png"
      }
    }
  }
}<p>사전 필터링은 <a href="https://www.elastic.co/docs/solutions/search/vector/knn#knn-search-filter-example">knn 검색과</a> <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-knn-query#knn-query-filtering">knn 쿼리</a> 모두에 사용할 수 있습니다:</p>{
  "query": {
    "knn": {
      "field": "image-vector",
      "query_vector": [-5, 9, -12],
      "k": 5,
      "filter": {
        "term": {
          "file-type": "png"
        }
      }
    }
  }
}<h4>사전 필터링 최적화</h4><p>사전 필터링의 성능을 보장하기 위해 적용할 수 있는 몇 가지 최적화가 있습니다.</p><p>필터가 매우 제한적인 경우 정확한 검색으로 전환할 수 있습니다. 비교할 벡터가 적을 때는 필터를 만족하는 소수의 문서에 대해 정확한 검색을 수행하는 것이 더 빠릅니다.</p><p>이것은 <a href="https://github.com/apache/lucene/blob/eb876b618da5d04c1ad14b04a48321638318493a/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java#L218">Lucene과</a> Elasticsearch에서 자동으로 적용되는 최적화입니다.</p><p>또 다른 최적화 방법은 필터를 만족하지 않는 벡터를 무시하는 것입니다. 대신 이 메서드는 필터를 통과한 필터링된 벡터의 이웃을 확인합니다. 이 접근 방식은 필터링된 벡터를 고려하지 않고 현재 경로에 연결된 벡터를 계속 탐색하므로 비교 횟수를 효과적으로 줄일 수 있습니다.</p><p>이 알고리즘은 ACORN-1이며, 그 과정은 <a href="https://www.elastic.co/search-labs/blog/filtered-hnsw-knn-search">이 블로그 게시물에</a> 자세히 설명되어 있습니다.</p><h2>문서 수준 보안을 사용한 필터링</h2><p><a href="https://www.elastic.co/docs/deploy-manage/users-roles/cluster-or-deployment-auth/controlling-access-at-document-field-level#document-level-security">DLS(문서 수준 보안)</a> 는 사용자 역할이 검색할 수 있는 문서를 지정하는 Elasticsearch 기능입니다.</p><p>DLS는 쿼리를 사용하여 수행됩니다. 역할에는 인덱스와 연결된 쿼리가 있을 수 있으며, 이 쿼리는 해당 역할에 속한 사용자가 인덱스에서 검색할 수 있는 문서를 효과적으로 제한합니다.</p><p>역할 쿼리는 필터로 사용되어 <a href="https://github.com/elastic/elasticsearch/blob/c3a1cb34294e902a9f46d7e840ea09965019f456/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/accesscontrol/SecurityIndexReaderWrapper.java#L92">일치하는 문서를 검색하고</a> 비트셋으로 캐시됩니다. 그런 다음 이 비트셋은 기본 Lucene 리더를 래핑하는 데 사용되므로 쿼리에서 반환된 문서, 즉 인덱스에 존재하고 삭제되지 않은 문서만 <em>라이브</em>문서로 간주됩니다.</p><p>knn 쿼리를 수행하기 위해 리더에서 라이브 문서가 검색되므로 사용자가 사용할 <a href="https://github.com/apache/lucene/blob/a211d30097a8e3264d3ef073a054bd31eb847231/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java#L196">수 있는 문서만 고려됩니다.</a> 프리필터가 있는 경우 DLS 문서가 프리필터에 <a href="https://github.com/apache/lucene/blob/a211d30097a8e3264d3ef073a054bd31eb847231/lucene/core/src/java/org/apache/lucene/search/AbstractKnnVectorQuery.java#L204">추가됩니다</a>.</p><p>즉, DLS 필터링은 근사 벡터 검색을 위한 프리필터로 작동하며 성능에 미치는 영향과 최적화가 동일합니다.</p><p>정확한 검색을 사용하는 DLS는 필터를 적용하는 것과 동일한 이점이 있습니다. DLS에서 검색되는 문서가 적을수록 정확한 검색의 성능이 향상됩니다. DLS 역할이 매우 제한적인 경우 대략적인 검색 대신 정확한 검색을 사용하는 것도 고려할 수 있습니다.</p><h2>벤치마킹</h2><p>Elasticsearch에서는 벡터 검색 필터링이 효율적인지 확인하고자 합니다. 벡터 <a href="https://elasticsearch-benchmarks.elastic.co/#tracks/so_vector/nightly/default/90d">필터링에 대한 특정 벤치마크가</a> 있어 다양한 필터링을 통해 대략적인 벡터 검색을 수행하여 벡터 검색이 관련성 있는 결과를 최대한 빠르게 검색할 수 있도록 합니다.</p><p>ACORN-1 도입 시 <a href="https://elasticsearch-benchmark-analytics.elastic.co/app/dashboards#/view/43b63e80-5ba2-11ed-aede-a742809feed4?_g=(refreshInterval:(pause:!t,value:60000),time:(from:'2025-05-28T01:27:58.456Z',to:'2025-06-30T13:53:26.430Z'))&amp;_a=()">개선</a> 사항을 확인하세요. 필터를 통과한 벡터가 2개% 뿐인 테스트의 경우 쿼리 지연 시간은 원래 지속 시간의 55% 로 줄어듭니다:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt820cb0b715cf291c/6a17e227dbb4ff8d49fb5615/3eac3748a33376fc97d957364a5c1f5108d5c58b-1023x896.png" alt="" /><h2>결론</h2><p>필터링은 검색의 필수적인 부분입니다. 벡터 검색에서 필터링이 제대로 작동하는지 확인하고 장단점과 최적화를 이해하는 것이 효율적이고 정확한 검색의 성패를 좌우합니다.</p><p>필터링은 벡터 검색의 성능에 영향을 미칩니다:</p><ul><li><p>필터링을 사용하면 정확한 검색이 더 빠릅니다. 필터링이 충분히 제한적인 경우 대략적인 검색 대신 정확한 검색을 사용하는 것이 좋습니다. 이것은 Elasticsearch의 자동 최적화입니다.</p></li><li><p>사전 필터링 사용 시 대략적인 검색 속도가 느려집니다. 사전 필터링을 사용하면 검색 속도가 느려지는 대신 필터와 일치하는 상위 k개의 결과를 얻을 수 있습니다.</p></li><li><p>사후 필터링은 필터를 적용할 때 필터를 통해 필터링될 수 있으므로 반드시 상위 k개의 결과를 검색하지는 않습니다.</p></li></ul><p>행복한 필터링!</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/vector-search-filtering</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/vector-search-filtering</guid>
    <category><![CDATA[벡터 데이터베이스]]></category>
    <category><![CDATA[Lucene]]></category>
    <category><![CDATA[Elastic 내부]]></category>
    <dc:creator><![CDATA[Carlos Delgado]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt39ede1736e0f1456/6a17e2282f4a5c5031fa8843/03b1dd4c7bda4fbabd8e374bc2e4f12d5be6ef5f-1600x1150.png" length="0" type="image/png"/>
    <pubDate>Wed, 03 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>