티스토리 뷰

 

 

failed to create query: [knn] queries are only supported on [dense_vector] fields

 

여기서 예시는 knn으로 들었지만, _search를 이용한 Elasticsearch의 검색 알고리즘을 사용할 때 발생하는 문제이다.

 

말 그대로 knn 쿼리를 날린 필드가 dense_vector의 형태가 아니란 것이다.

 

에러를 발생시켜보자

테스트 코드는 엘라스틱 서치의 kNN search 가이드에서 가져왔다.

 

우선 테스트를 위해 데이터를 삽입한다.

POST image-index/_bulk?refresh=true
{ "index": { "_id": "1" } }
{ "image-vector": [1, 5, -20], "title-vector": [12, 50, -10, 0, 1], "title": "moose family", "file-type": "jpg" }
{ "index": { "_id": "2" } }
{ "image-vector": [42, 8, -15], "title-vector": [25, 1, 4, -12, 2], "title": "alpine lake", "file-type": "png" }
{ "index": { "_id": "3" } }
{ "image-vector": [15, 11, 23], "title-vector": [1, 5, 25, 50, 20], "title": "full moon", "file-type": "jpg" }

데이터를 보면 나는 분명히 정상적으로 값을 삽입했다.

GET image-index/_doc/1
// 검색결과
{
  "_index": "image-index",
  "_id": "1",
  "_version": 2,
  "_seq_no": 3,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "image-vector": [1, 5, -20],
    "title-vector": [12, 50, -10, 0, 1],
    "title": "moose family",
    "file-type": "jpg"
  }
}

값이 정상적으로 출력된다.

 

값이 있으니 knn search를 사용해보자.

POST image-index/_search
{
  "knn": {
    "field": "image-vector",
    "query_vector": [-5, 9, -12],
    "k": 10,
    "num_candidates": 100
  },
  "fields": [ "title", "file-type" ]
}

이러면 에러가 나온다.

{
  "error": {
    "root_cause": [
      {
        "type": "query_shard_exception",
        "reason": "failed to create query: [knn] queries are only supported on [dense_vector] fields",
        "index_uuid": "g25RtpnCRZ6bVh1N-jwLgA",
        "index": "image-index"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "dfs",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "image-index",
        "node": "079lDABdT-urjBSUxDLqvA",
        "reason": {
          "type": "query_shard_exception",
          "reason": "failed to create query: [knn] queries are only supported on [dense_vector] fields",
          "index_uuid": "g25RtpnCRZ6bVh1N-jwLgA",
          "index": "image-index",
          "caused_by": {
            "type": "illegal_argument_exception",
            "reason": "[knn] queries are only supported on [dense_vector] fields"
          }
        }
      }
    ]
  },
  "status": 400
}

데이터는 분명히 있고, 벡터값이 만들어져 있는 데 왜 에러가 왜 발생할까?

 

일단 위 매서드 요청 순서는 에러를 발생시키기 위해 엘라스틱 서치에서 제공하는 가이드대로 따라가지 않았다.

 

에러 원인은

 

ES의 인덱스는 일반적인 nosql 들과는 다르게 PUT 매서드를 통해서 인덱스의 데이터 타입을 사전에 지정할 수 있는데,

 

데이터의 properties를 사전에 mapping하지 않아 ES가 마음대로 데이터 타입을 지정해버려서 생기는 문제다.

 

아래가 위 에러를 발생시키지 않기 위해 들어가야하는 초기 설정인 PUT 매서드다.

PUT image-index
{
  "mappings": {
    "properties": {
      "image-vector": {
        "type": "dense_vector",
        "dims": 3,
        "index": true,
        "similarity": "l2_norm"
      },
      "title-vector": {
        "type": "dense_vector",
        "dims": 5,
        "index": true,
        "similarity": "l2_norm"
      },
      "title": {
        "type": "text"
      },
      "file-type": {
        "type": "keyword"
      }
    }
  }
}

 

이제 수정하는 방법을 알아보자

 

수정법

가장 빠른 방법은 인덱스를 통으로 날려버리고 다시 만드는 것이다.

 

하지만 이미 인덱스에 데이터를 삽입했는데 재삽입이 어렵다면, 생각보다 조금 귀찮아진다.

 

우선 데이터가 index에 들어가게되면, 타입에 따라서 index에 mapping된 properties가 변경되지 않을 수 있다.

 

위 데이터가 대표적인 예이다.

 

image-index 에 매핑된 properties를 까보면 아래와 같다.

 

knn 서치를 사용하기 위해서는 image-vector와 title-vector가 dense_vector 형식이어야 한다.

 

그런데 ES가 자기맘대로 long 타입으로 넣어버렸기 때문에 검색이 안되는 것이었다...

 

실제로 알고리즘들을 쓸 때 이 검색 알고리즘은 타입을 반드시 dense_vector로 지정해야합니다. 라는 문구가 있는 것을 확인할 수 있다.

 

 

이제 삽입된 데이터가 있을 때의 수정법을 알아보자.

1. 타입 직접 변경

이게 아까 언급한 타입에 따라서 index에 mapping된 properties가 변경되지 않는 방법이다.

PUT image-index/_mapping
{
  "properties": {
    "image-vector": {
      "type": "dense_vector",
      "dims": 3
    },
    "title-vector": {
      "type": "dense_vector",
      "dims": 5
    }
  }
}

 

이번 예시에선 아래와 같은 에러를 발생시킨다.

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "mapper [title-vector] cannot be changed from type [long] to [dense_vector]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "mapper [title-vector] cannot be changed from type [long] to [dense_vector]"
  },
  "status": 400
}

 

2. 멀티 필드 사용

image-vector 필드를 long 타입으로 유지하고, dense_vector 데이터 타입으로 새로운 필드를 추가하는 방식이다. 이러면 동일한 필드에 두 가지 데이터 타입을 동시에 사용할 수 있다.

PUT image-index/_mapping
{
  "properties": {
    "image-vector": {
      "type": "long",
      "fields": {
        "dense": {
          "type": "dense_vector",
          "dims": 3
        }
      }
    }
  }
}

 

3. 새로운 인덱스로 재인덱스(reindex)하기

제대로 매핑 정보를 세팅해놓은 인덱스로 데이터를 그대로 넘기는 방식이다. 이것도 데이터를 넘길 수 있는 타입으로 잘 만들어 놓았는지 확인해야한다.

 

image-indexx 라는 인덱스를 재생성

PUT image-indexx
{
  "mappings": {
    "properties": {
      "image-vector": {
        "type": "dense_vector",
        "dims": 3,
        "index": true,
        "similarity": "l2_norm"
      },
      "title-vector": {
        "type": "dense_vector",
        "dims": 5,
        "index": true,
        "similarity": "l2_norm"
      },
      "title": {
        "type": "text"
      },
      "file-type": {
        "type": "keyword"
      }
    }
  }
}

reindex 쿼리

POST /_reindex
{
  "source": {
    "index": "image-index"
  },
  "dest": {
    "index": "image-indexx"
  }
}

 

마치며

별 거 아닌 문제였는데, ES의 index가 nosql db라는 생각에

 

데이터가 아무렇게나 들어가도 되지 않나?  

 

라는 생각에 묶여있어서 너무 오래 붙잡혀 있었다.

 

이 포스팅이 내가 시간을 쓴만큼 누군가에겐 도움이 됐으면 좋겠다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함