벡터 유사도 계산을 스크립트로(Painless Scripting Extension)
OpenSearch는 knn_vector
필드에 대해 벡터 거리 계산 함수를 Painless 스크립트 내에서 직접 사용할 수 있도록 확장 기능을 제공한다.
이 기능은 기존의 knn_score
스크립트 대신 보다 유연하고 커스터마이징 가능한 방식으로 벡터 유사도를 계산할 수 있게 해준다.
1. Painless 확장 기능이란?
기본적으로 OpenSearch의 Painless 스크립트는 보안상의 이유로 제한된 함수만 사용할 수 있다. 하지만 k-NN 플러그인을 통해 다음과 같은 거리/유사도 함수가 추가로 지원된다.
함수명 | 설명 |
---|---|
l2Squared() |
L2 거리(유클리드 거리)의 제곱 계산 |
l1Norm() |
L1 거리(맨해튼 거리) 계산 |
cosineSimilarity() |
코사인 유사도 계산 |
hamming() |
해밍 거리 계산 (2.16 이상, binary 필드용) |
2. 기본 사용 예시
GET my-knn-index-2/_search
{
"size": 2,
"query": {
"script_score": {
"query": {
"bool": {
"filter": {
"term": { "color": "BLUE" }
}
}
},
"script": {
"source": "1.0 + cosineSimilarity(params.query_value, doc[params.field])",
"params": {
"field": "my_vector",
"query_value": [9.9, 9.9]
}
}
}
}
}
-
field
:knn_vector
타입 필드 -
query_value
: 쿼리 벡터 (필드와 동일한 차원 필요) -
cosineSimilarity
,l2Squared
,l1Norm
등을 활용해 유사도/거리 계산 가능
3. 각 함수 설명
함수 | 시그니처 | 설명 |
---|---|---|
l2Squared |
float l2Squared(float[] query, doc['vec']) |
유클리드 거리의 제곱. 값이 작을수록 유사. |
l1Norm |
float l1Norm(float[] query, doc['vec']) |
맨해튼 거리. |
cosineSimilarity |
float cosineSimilarity(float[] query, doc['vec']) |
코사인 유사도. 일반적으로 0~1 범위. |
cosineSimilarity (최적화) |
float cosineSimilarity(query, doc, norm) |
쿼리 벡터의 크기를 별도로 넘겨 반복 계산 방지 |
hamming |
float hamming(float[] query, doc['vec']) |
해밍 거리. 벡터 값이 정수여야 하며, binary 또는 long 타입 지원 (2.16+) |
4. 예외 및 주의사항
-
벡터 차원이 다르면:
IllegalArgumentException
발생 -
벡터 필드가 비어 있으면:
IllegalStateException
발생
→ 아래와 같이 size 체크로 회피 가능:
"doc[params.field].size() == 0 ? 0 : 1 / (1 + l2Squared(params.query_value, doc[params.field]))"
- 코사인 유사도는 0 벡터 사용 금지
→ 크기가 0인 벡터는 계산 불가 → 예외 발생
5. 실전 활용 팁
-
필터 조건이 있는 벡터 검색에 매우 유용 (
bool
+script_score
조합) -
벡터 간 거리를 기반으로 커스텀 랭킹 계산 로직 구현 가능
-
cosineSimilarity
는 자주 쓰이는 경우 norm 미리 계산하여 속도 개선 가능 -
스코어가
0~1
범위로 제한되지 않으므로 결과 정규화 필요 시 수식 추가
마무리
OpenSearch의 Painless 스크립팅 확장 기능은 단순한 벡터 검색을 넘어서 복잡한 랭킹 로직, 조건부 벡터 스코어링, 커스텀 점수 조정 등의 고급 기능 구현을 가능하게 한다.
Approximate k-NN이나 knn_score
기반 스크립트보다 더 높은 유연성이 필요한 경우에 적극 활용할 수 있다.