엘라스틱서치에서 데이터 타입: 키워드는 텍스트 타입과는 다르게 전문검색용으로 사용하지 못해요. 왜?

냐하면 키워드 타입은 텍스트 타입과 다르게 분석하고 저장하는 방식에서 차이가 나기 때문이에요.

 

텍스트 타입에는 standard analyzer가 사용되는 반면에 키워드 타입에는 keyword analyzer가 사용돼요. 예전에 한 번 써봤던 analyze API를 사용해서 한 번 볼게요.

POST /_analyze
{
  "text": "Harry Potter and the Deathly Hallows",
  "analyzer": "keyword"
}



{
  "tokens" : [
    {
      "token" : "Harry Potter and the Deathly Hallows",
      "start_offset" : 0,
      "end_offset" : 36,
      "type" : "word",
      "position" : 0
}]}

해리포터와 죽음의 성물들을 예로 보면 응답 값에서 토큰이 하나로 처음부터 끝까지 하나의 토큰으로 나온 것을 볼 수 있어요. 만약 이렇게 '해리포터와 죽음의 성물'이라고 키워드 타입으로 인덱싱 해 놓았다면 '죽음의 성물' 이라고 검색해서는 결과를 찾아낼 수 없어요 꼭 '해리포터와 죽음의 성물' 이라고 검색해야만 나오는 거죠. 그럼 지금까지 많이 봐왔지만 그냥 스윽 넘어갔던 부분을 조금 더 정확하게 다시 한번 볼까요?

"title" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
}}}

아주 정확하지는 않지만 이런 뜻이에요. 타이틀이라는 필드는 텍스트 타입입니다. 텍스트 타입인데, 이 타이틀이라는 필드에는 키워드라는 필드를 가지고 있고 그 건 키워드라는 타입이에요. 그리고 256자가 넘어가면 무시할 겁니다.

 

그럼 정말 그런지 한 번 볼까요? 해리포터와 죽음의 성물을 두 가지 방식으로 찾아볼게요.

먼저 hallows라는 term을 가지고 찾아볼게요.

POST /books/_search
{
  "query": {
    "match": {
      "title": "hallows"
}}}


"took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },

찾아왔어요. 한 가지 알아야 할 건, Hallows로 검색해도 찾아지고 hallows로 검색해도 찾아지지만 Hallow도 안 되고 hallow도 안 돼요.

 

자 그럼 다음을 보기 전에 키바나에서 dev tools 기능 하나 보고 가실게요.

이렇게 자동완성으로 만들면 FIELD: TEXT 이런 형식으로 쿼리를 작성하라고 나오는데 titl 까지만 써도 title 필드에서 찾을 건지, title.keyword 필드에서 찾을 건지 딱 알아서 딱 알려주네요.

 

결과를 먼저 말하자면 title.keyword 필드에서는 Hallows도 hallows도 다 안돼요. 찾을 수가 없어요. 아무것도. 또 'harry potter and the deadly hallows' 도 안 돼요. 대소문자 까지 모두 구분해서 'Harry Potter and the Deathly Hallows'라고 검색을 해야 결과가 나와요

POST /books/_search
{
  "query": {
    "match": {
      "title.keyword": "Harry Potter and the Deathly Hallows"
}}}


{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
  ...

 

이렇게 빡빡하게 구는 키워드 타입을 그럼 어디에 써야 할까요?

 

키워드 타입으로 인덱싱 한 필드 값은 집계(aggregation)와 정렬(sorting)에 사용할 수 있어요. 예를 들어 books 인덱스에 title을 오름차순으로 정렬해서 보여줘 라는 요청은 이렇게 작성하고 그 결괏값은 아래와 같아요.

POST /books/_search
{
  "sort": [
    {
      "title.keyword": {
        "order": "asc"
}}]}



 "hits" : {
    "total" : {
      "value" : 7,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
...
        },
        "sort" : [
          "Harry Potter and the Chamber of Secrets"
        ]
      },
      {
        "_index" : "books",
...
        },
        "sort" : [
          "Harry Potter and the Deathly Hallows"
        ]
      },
      {
...
        "sort" : [
          "Harry Potter and the Goblet of Fire"
        ]
      },
      {
...
        },
        "sort" : [
          "Harry Potter and the Half-Blood Prince"
        ]
      },
      {
...
        },
        "sort" : [
          "Harry Potter and the Order of the Phoenix"
        ]
      },
      
...

 

 

물론 text 데이터 타입으로도 정렬과 집계 같은 기능을 사용할 수는 있지만 메모리를 많이 차지하고 추천하지 않는다고 공식문서에서 이야기하고 있어요. 키워드 타입에 대한 보다 자세한 사항을 확인하세요.

 

그럼 오늘도 여기까지.