semantic_text 활용
원본 보기semantic_text 활용
이 튜토리얼에서는 semantic_text 필드 타입을 사용해 시맨틱 검색을 구성하는 방법을 단계별로 안내합니다. 끝까지 따라 하면 다음을 할 수 있습니다.
semantic_text필드가 포함된 인덱스 매핑 생성- 벡터 임베딩으로 자동 변환되는 문서 인제스트
- Query DSL과 ES|QL 양쪽으로 시맨틱 검색 쿼리 실행
semantic_text 필드 타입은 합리적인 기본값으로 인제스트 시점에 추론을 수행해 추론 워크플로를 단순화합니다. 모델 관련 설정과 파라미터를 정의하거나 추론 인제스트 파이프라인을 만들 필요가 없습니다.
Elastic Stack에서 시맨틱 검색을 구현할 때는 semantic_text 워크플로 사용을 권장합니다. 인덱싱과 쿼리 설정을 더 세밀하게 제어해야 한다면 전체 추론 워크플로를 대신 사용할 수 있습니다(자세한 내용은 Inference API를 활용한 시맨틱 검색 참조).
이 튜토리얼은 Elastic Inference Service(EIS)를 사용하지만, Inference API가 지원하는 모든 서비스와 모델을 사용할 수 있습니다.
- 이 튜토리얼은 Elastic Inference Service(EIS)를 사용하며, 이 서비스는 Elastic Cloud Hosted 배포와 Serverless 프로젝트에서 자동으로 활성화됩니다.
자체 관리 클러스터에서도 EIS를 사용할 수 있습니다.
- Elastic Inference Service 이외의 추론 서비스로
semantic_text필드 타입을 사용하려면 Create inference API로 추론 엔드포인트를 먼저 생성해야 합니다.
이 튜토리얼의 curl 예제를 실행하려면 다음 환경 변수를 설정하세요.
export ELASTICSEARCH_URL="your-elasticsearch-url"
export API_KEY="your-api-key"
API 키를 생성하려면 전역 검색 창에서 API keys를 검색하세요. 엔드포인트와 자격 증명을 찾는 방법 자세히 보기.
semantic_text 필드가 포함된 대상 인덱스를 생성합니다. 이 필드는 추론 엔드포인트가 입력 텍스트에서 생성한 벡터 임베딩을 저장합니다.
추론은 Elastic Inference Service에서 실행하거나 직접 운영하는 ML 노드에서 실행할 수 있습니다. 다음 예제는 두 가지 경우를 모두 보여 줍니다.
PUT semantic-embeddings
{
"mappings": {
"properties": {
"content": {
"type": "semantic_text"
}
}
}
}
- 생성된 임베딩을 담을 필드의 이름입니다.
- 임베딩을 담을 필드는
semantic_text필드입니다.inference_id가 제공되지 않았으므로 기본 추론 엔드포인트가 사용됩니다.
PUT semantic-embeddings
{
"mappings": {
"properties": {
"content": {
"type": "semantic_text",
"inference_id": ".elser-2-elasticsearch"
}
}
}
}
- 생성된 임베딩을 담을 필드의 이름입니다.
- 임베딩을 담을 필드는
semantic_text필드입니다. elasticsearch서비스용으로 사전 구성된.elser-2-elasticsearch추론 엔드포인트가 사용됩니다. 다른 추론 서비스를 사용하려면 Create inference API로 추론 엔드포인트를 먼저 생성한 뒤,inference_id파라미터를 사용해semantic_text필드 매핑에 지정해야 합니다.
curl -X PUT "${ELASTICSEARCH_URL}/semantic-embeddings" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"mappings": {
"properties": {
"content": {
"type": "semantic_text"
}
}
}
}'
- 생성된 임베딩을 담을 필드의 이름입니다.
- 임베딩을 담을 필드는
semantic_text필드입니다.inference_id가 제공되지 않았으므로 기본 추론 엔드포인트가 사용됩니다.
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "semantic-embeddings"
}
기본 추론 엔드포인트에 의존하는 방식은 처음 시작할 때 편리하지만, 프로덕션 환경에서는 inference_id를 명시적으로 지정할 것을 권장합니다. 기본 엔드포인트는 버전과 배포 유형에 따라 달라질 수 있어 서로 다른 임베딩 모델이 섞인 인덱스가 만들어지고 다중 인덱스 검색에서 랭킹 문제가 발생할 수 있습니다. 자세한 내용은 인덱스 간에 임베딩 모델이 섞일 때 발생할 수 있는 문제를 참조하세요.
밀집 벡터 임베딩을 사용하는 대규모 배포에서는 BBQ 같은 양자화 전략을 구성해 메모리 사용량을 크게 줄일 수 있습니다. 고급 구성은 벡터 스토리지 최적화를 참조하세요.
웹 크롤러나 커넥터로 인덱스를 생성하는 경우, 해당 인덱스에 semantic_text 필드가 포함되도록 인덱스 매핑을 업데이트해야 합니다. 매핑을 업데이트한 뒤에는 전체 웹 크롤 또는 전체 커넥터 동기화를 실행해야 합니다. 이렇게 하면 기존 문서가 모두 재처리되어 새 시맨틱 임베딩으로 갱신되며, 업데이트된 데이터에 시맨틱 검색을 사용할 수 있습니다.
인덱스 매핑이 준비되면 데이터를 추가할 수 있습니다. 문서를 인덱싱하면 Elasticsearch가 semantic_text 필드의 내용을 구성된 추론 엔드포인트로 자동 전송해 벡터 임베딩을 생성하고 문서에 저장합니다.
_bulk API로 샘플 문서 몇 개를 인제스트해 보세요.
POST _bulk
{ "index": { "_index": "semantic-embeddings", "_id": "1" } }
{ "content": "After running, cool down with light cardio for a few minutes to lower your heart rate and reduce muscle soreness." }
{ "index": { "_index": "semantic-embeddings", "_id": "2" } }
{ "content": "Marathon plans stress weekly mileage; carb loading before a race does not replace recovery between hard sessions." }
{ "index": { "_index": "semantic-embeddings", "_id": "3" } }
{ "content": "Tune cluster performance by monitoring thread pools and refresh interval." }
curl -X POST "${ELASTICSEARCH_URL}/_bulk" \
-H "Content-Type: application/x-ndjson" \
-H "Authorization: ApiKey ${API_KEY}" \
--data-binary @- << 'EOF'
{ "index": { "_index": "semantic-embeddings", "_id": "1" } }
{ "content": "After running, cool down with light cardio for a few minutes to lower your heart rate and reduce muscle soreness." }
{ "index": { "_index": "semantic-embeddings", "_id": "2" } }
{ "content": "Marathon plans stress weekly mileage; carb loading before a race does not replace recovery between hard sessions." }
{ "index": { "_index": "semantic-embeddings", "_id": "3" } }
{ "content": "Tune cluster performance by monitoring thread pools and refresh interval." }
EOF
{
"errors": false,
"took": 400,
"items": [
{
"index": {
"_index": "semantic-embeddings",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1,
"status": 201
}
},
{
"index": {
"_index": "semantic-embeddings",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 1,
"_primary_term": 1,
"status": 201
}
},
{
"index": {
"_index": "semantic-embeddings",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"_seq_no": 2,
"_primary_term": 1,
"status": 201
}
}
]
}
false는 모든 인덱싱 작업이 오류 없이 완료되었음을 나타냅니다.- 각 문서가 성공적으로 생성되었습니다.
semantic_text필드의 내용은 임베딩 생성을 위해 구성된 추론 엔드포인트로 자동 전송됩니다.
오류가 보이면 인덱스 매핑과 추론 엔드포인트가 올바르게 구성되었는지 확인하세요.
데이터가 인제스트되고 자동으로 임베딩되면 시맨틱 검색으로 조회할 수 있습니다. Query DSL 또는 ES|QL 문법을 사용할 수 있습니다.
Query DSL 방식은 semantic_text 필드에 match 쿼리 타입을 사용합니다.
GET semantic-embeddings/_search
{
"query": {
"match": {
"content": {
"query": "What causes muscle soreness after running?"
}
}
}
}
- 검색을 수행할
semantic_text필드입니다. - 쿼리 텍스트입니다.
ES|QL 방식은 match(:) 연산자를 사용하며, 이 연산자는 semantic_text 필드를 자동으로 감지해 해당 필드에서 검색을 수행합니다. 이 쿼리는 METADATA _score를 사용해 _score 기준 내림차순으로 정렬합니다.
POST /_query?format=txt
{
"query": """
FROM semantic-embeddings METADATA _score
| WHERE content: "How to avoid muscle soreness while running?"
| SORT _score DESC
| LIMIT 1000
"""
}
METADATA _score절은 각 문서의 관련도 점수를 반환합니다.- match(
:) 연산자가semantic_text필드를 감지해content에서 시맨틱 검색을 수행합니다. - 점수 내림차순으로 정렬해 가장 관련성 높은 결과를 먼저 표시합니다.
- 결과를 1000개 문서로 제한합니다.
curl -X GET "${ELASTICSEARCH_URL}/semantic-embeddings/_search" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"query": {
"match": {
"content": {
"query": "What causes muscle soreness after running?"
}
}
}
}'
curl -X POST "${ELASTICSEARCH_URL}/_query?format=txt" \
-H "Content-Type: application/json" \
-H "Authorization: ApiKey ${API_KEY}" \
-d '{
"query": "FROM semantic-embeddings METADATA _score | WHERE content: \"How to avoid muscle soreness while running?\" | SORT _score DESC | LIMIT 1000"
}'
두 쿼리 모두 시맨틱 관련도 순으로 정렬된 문서를 반환합니다. 달리기와 근육통에 관한 문서가 쿼리와 의미적으로 가장 가깝기 때문에 가장 높은 점수를 받고, 클러스터 성능에 관한 문서는 더 낮은 점수를 받습니다.
{
"took": 87,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 21.098728,
"hits": [
{
"_index": "semantic-embeddings2",
"_id": "1",
"_score": 21.098728,
"_source": {
"content": "After running, cool down with light cardio for a few minutes to lower your heart rate and reduce muscle soreness."
}
},
{
"_index": "semantic-embeddings2",
"_id": "2",
"_score": 8.030467,
"_source": {
"content": "Marathon plans stress weekly mileage; carb loading before a race does not replace recovery between hard sessions."
}
}
]
}
}
- 문서는
_score기준으로 정렬됩니다. 점수가 높을수록 쿼리와의 시맨틱 관련도가 높습니다. _source에는 원본 문서 텍스트가 담깁니다. 임베딩은 내부적으로 저장되며 기본적으로 응답에서 제외됩니다.
content | _score
-----------------------------------------------------------------------------------------------------------------+------------------
After running, cool down with light cardio for a few minutes to lower your heart rate and reduce muscle soreness.|26.408897399902344
Marathon plans stress weekly mileage; carb loading before a race does not replace recovery between hard sessions.|11.229613304138184
Tune cluster performance by monitoring thread pools and refresh interval. |0.3044795095920563 | 1.235689
semantic_text필드가 지원하는 모든 쿼리 타입 개요와 사용 시점에 대한 안내는semantic_text필드 쿼리하기를 참조하세요.- 하이브리드 검색에서
semantic_text를 사용하려면 단계별 가이드가 담긴 이 노트북을 참조하세요. - ELSER 엔드포인트 최적화 방법에 대한 자세한 내용은 모델 문서의 ELSER 권장 사항 섹션을 참조하세요.
- 모델 오토스케일링에 대해 자세히 알아보려면 학습된 모델 오토스케일링 페이지를 참조하세요.
- 밀집 벡터 임베딩 사용 시 스토리지와 검색 성능을 최적화하는 방법은 벡터 스토리지 최적화를 참조하세요.