Skip to main content

Elasticsearch 7.3 활용해보기 #7 – index의 갱신

현재 만들고 있는 서비스에서는 MariaDB와 연동하여 검색데이터를 색인하고 있습니다. MariaDB에서 변경되는점을 바로 Elasticsearch에서 갱신할 수 없기 때문에 일정시간마다 동기화(?) 해주는 방식으로 운영하고 있습니다.

물론 -_-.. 할수는 있지만… 성능적으로 볼때 잦은 update는 자료 자체가 수정되는게 아닌 키를 변경하고 새로운 데이터가 추가되는 작업으로서 검색성능을 떨어뜨릴 수 있기 때문에 최적의 indx 상태를 유지하기 위해서 새로 생성하는게 좋다고 하더군요… 새로 생성하는데 얼마 걸리지도 않습니다. (쿨럭..)

그러나, 새로 만드는 동안에는 index를 사용할 수 없음으로 기존의 index로 운영하고 있다가 새로 생성된 index의 작업이 완료되면, 교체 해줘야합니다. 이때 index의 이름을 알아야 제대로 쿼리할 수 있는데요….
alias…(별칭)기능을 통해서 구index에서 신index로 alias를 옴겨주는 원리로 서비스에 지장없이 운영할 수 있게 됩니다.

alias 지정하기

_aliases api를 이용해서 지정하거나 제거할 수 있습니다.

index에 별칭을 추가해보면…..

POST /_aliases
{
    "actions" : [
        { "add" : { "index" : "my_index_190925102459", "alias" : "my_index" } }
    ]
}

이렇게 해두면 쿼리의 index를 바꾸지 않고 my_index로서 계속해서 쿼리를 할 수 있게됩니다.

같은 이름의 index가 있으면 안되기 때문에 구index의 이름을 제거하고 해야합니다. 이때는 add대신 remove를 줘서 제거할 수 있습니다.

POST /_aliases
{
    "actions" : [
        { "remove" : { "index" : "my_index_190925102459", "alias" : "my_index" } }
    ]
}

쿼리의 형태를 보면 , 로 연결하여 여러개가 동시에 처리되도록도 가능합니다.

실제 구현은 PHP로 했습니다.

logstash도 좋지만… 어느정도 컨트롤도 했으면 해서 Elasticsearch-PHP 라이브러리를 이용하여 사용하고 있습니다.
자세한 내용 : https://www.elastic.co/guide/en/elasticsearch/client/php-api/7.0/index.html

<?php
use Elasticsearch\ClientBuilder;

class ES_Api {
	var $client;

	public function __construct(){
        ini_set("display_errors","1");
        $this->client = ClientBuilder::create()->setHosts(array('my_host'))->build();
    }

	//add alias
    private function addAlias($index,$alias){
        $params = [
            'index' => "{$index}",
            'name' => "{$alias}",
            'body' => []
        ];
        $this->client->indices()->putAlias($params);
    }

    //index list
    private function get_index_simular($index){
        $ret = array();
        $res = $this->client->cat()->indices();
        foreach($res as $k => $row){
            if(strpos($row['index'],$index) !== false){
                $ret[] = $row['index'];
            }
        }
        return $ret;
    }

    //작업후 삭제 및 새로운 별칭을 추가
    private function change_work_index($alias,$new_index){
        $post_fix = "_";

        $res = $this->get_index_simular($alias.$post_fix);
        foreach($res as $k => $index){
            if($index != $new_index){
                $this->RemoveIndex($index);
            }
        }
        $this->addAlias($new_index,$alias);
    }
}

index명의 alias를 간단한 함수로 변경할수 있게 됩니다. 위 코드는 개념적으로 작성된 것이라 -_-… 함수만 가져다 활용하실 수 있습니다.

오늘은 여기까지 입니다. 다음에는 elasticsearch-php를 좀더 알아봅시다.

Elasticsearch 7.3 활용해보기 #6 – _msearch 여러쿼리를 한번에

계획 없이 포스팅 하기 시작해서 언제까지 elasticsearch에 대해서 적을지에 대한 계획은 없습니다.

기존에 _search api를 통해서 검색을 해보았는데, 실무에 활용하다보니 갈수록 쿼리가 많아지게 되어서 찾아보니… 여러개의 쿼리를 한번에 보낼 수 있는 방법이 있었습니다.

쿼리가 호출되는 단위를 묶어주니 그만큼의 네크워크 지연시간이 줄어들 수 있겠죠. 전송량도 중요하지만, 전송되는 횟수도 속도에 영향을 많이 줍니다.

여러개의 쿼리 한번에 처리하기

이번에도 kibana console에서 처리해볼겁니다. 실제로는 PHP로 처리중이지만, PHP로 하는 것은 어느정도 여유가 되면 정리해 두겠습니다. #5에서 대량으로 자료를 등록한 _bulk api와 비슷합니다.

이용하는 api는 Multi Search… _msearch 입니다. 자세한 내용은 다음 링크에서 봐주세요.
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-multi-search.html

GET _msearch
{"index" : "my_index"}
{"query": { "query_string": {"fields": ["title","note"],"query": "*청산*"  }  },"size":"0" }
{"index" : "my_index"}
{"query": { "query_string": {"fields": ["title","note"],"query": "*별곡*"  }  } }
{"index" : "my_index"}
{"query": { "query_string": {"fields": ["title","note"],"query": "*별곡*"  }  } }

인덱스를 지정해주고 2라인이 한쌍이 되게 됩니다. 첫번째 줄은 인덱스를 지정해주고 두번째 줄은 쿼리를 작성합니다. _bulk와 마찬가지로 쿼리는 한줄에 다 작성해줘야합니다. (그렇지 않으면…… )

_msearch에서 count 구하기

이전 버전에서는 search_type을 count로 주면 검색되는 문서의 갯수를 알수 있엇지만, 현재 버전에서는 작동하지 않는것 같습니다. 그래서 쿼리에 “size”:”0″를 추가하여 내용을 생략한 갯수만 구해 올 수도 있습니다. (이거땜에 한참 해메였음)

{
  "took" : 2,
  "responses" : [
    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : null,
        "hits" : [ ]
      },
      "status" : 200
    },
    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 2,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "Dt4MH20BjjMy29Rvz-kp",
            "_score" : 1.0,
            "_source" : {
              "title" : "청산별곡",
              "note" : "살어리 살어리랏다 靑山에 살어리랏다. 멀위랑 달래 먹고 靑山에 살어리랏다.얄리얄리 얄랑셩 얄라리 얄라"
            }
          },
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "Ed4MH20BjjMy29Rvz-kp",
            "_score" : 1.0,
            "_source" : {
              "title" : "西京별곡",
              "note" : "西京이 아즐가 西京이 셔울히 마르는 위 두어렁셩 두어렁셩 다링디리"
            }
          }
        ]
      },
      "status" : 200
    },
    {
      "took" : 2,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 2,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "Dt4MH20BjjMy29Rvz-kp",
            "_score" : 1.0,
            "_source" : {
              "title" : "청산별곡",
              "note" : "살어리 살어리랏다 靑山에 살어리랏다. 멀위랑 달래 먹고 靑山에 살어리랏다.얄리얄리 얄랑셩 얄라리 얄라"
            }
          },
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "Ed4MH20BjjMy29Rvz-kp",
            "_score" : 1.0,
            "_source" : {
              "title" : "西京별곡",
              "note" : "西京이 아즐가 西京이 셔울히 마르는 위 두어렁셩 두어렁셩 다링디리"
            }
          }
        ]
      },
      "status" : 200
    }
  ]
}

3개의 블럭으로 데이터를 받아오는 것을 볼 수 있습니다. 갯수는 hits.total.value가 검색한 문서의 갯수입니다.

뭔가 쓸수록 매력이 있는것 같습니다. 이렇게 하고나서 40%정도의 속도 향상이 있었어요.. 노드를 추가하는 것이 더 성능이 좋을것 같긴합니다만… (환경이 -_-.. )
데이터의 상황에 따라서 took을 보면서 결정하도록 해야겠네요…

ㅂㄷㅂㄷ….

오늘은 여기까지입니다.

Elasticsearch 7.3 활용해보기 #5 – 한글검색

index이름/_search 를 이용한 한글 검색을 해보도록 합시다. 이게 참 단어가 인덱싱이 잘되어있어야 검색이 되는데, #4에서 봤던 userdict_ko.txt 같은 파일에 고유명사나 분해되면 안되는 단어들은 잘 기록해두도록 해야 합니다.

한글처리가 가능한 index 생성

검색을 하기위한 환경을 만들어봅니다. kibana console에 한글 처리가 가능한 index를 생성하기위해서 다음 쿼리를 console에 복붙(!!) 해봅니다.

PUT my_index
{
  "settings":{
      "number_of_shards":1,
      "number_of_replicas":0,
      "index":{
        "analysis":{
          "tokenizer":{
            "nori_tokenizer_mixed_dict":{
              "type":"nori_tokenizer",
              "decompound_mode":"mixed",
              "user_dictionary":"userdict_ko.txt"
            }
          },
          "analyzer": {
            "korean":{
              "type":"custom",
              "tokenizer":"nori_tokenizer_mixed_dict",
              "filter":[
                "nori_readingform","lowercase",
                "nori_part_of_speech_basic"]
              }
            },
            "filter":{
              "nori_part_of_speech_basic":{
                "type":"nori_part_of_speech",
                "stoptags":["E","IC","J","MAG","MAJ","MM","SP","SSC","SSO","SC","SE","XPN","XSA","XSN","XSV","UNA","NA","VSV"]
          }
        }
      }
    }
  }
}

생성되었다는 메시지를 확인하시고..

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "my_index"
}

대량 데이터 추가(bulk api)

대량(??)의 데이터를 5개 정도 추가해봅시다. 서버에서 해도 되지만, console에 직접 추가해도 잘 되더군요 ^^ 다만 데이터 부분은 한라인에 다 적어야 한다는 점은 주의해야 할 것 같습니다. -_- 모양땜에 엔터를 좀 넣어줬더니 잘 작동 안하더군요.

POST my_index/_bulk
{ "index":{} }
{ "title" : "청산별곡", "note" : "살어리 살어리랏다 靑山에 살어리랏다. 멀위랑 달래 먹고 靑山에 살어리랏다.얄리얄리 얄랑셩 얄라리 얄라" }
{ "index":{} }
{ "title" : "가시리", "note" : "가시리 가시리잇고 나는 버리고 가시리잇고 나는 위 증즐가 大平盛代 " }
{ "index":{} }
{ "title" : "정과정", "note" : "내 님을 그리워하여 울고 있으니 산 접동새와 내 신세가 비슷합니다." }
{ "index":{} }
{ "title" : "西京별곡", "note" : "西京이 아즐가 西京이 셔울히 마르는 위 두어렁셩 두어렁셩 다링디리" }
{ "index":{} }
{ "title" : "쌍화점", "note" : "만두가게에 만두 사러 갔더니 회회아비가 내 손목을 쥐었더라." }

이외에도 일괄적으로 업데이트 및 삭제도 가능하니 다음 자세한 내용을 참고하세요.
(자세한 내용: https://www.elastic.co/guide/en/elasticsearch/reference/7.3/docs-bulk.html )

추가된 데이터를 확인해보면….

GET my_index/_search
{
  "took" : 506,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "Dt4MH20BjjMy29Rvz-kp",
        "_score" : 1.0,
        "_source" : {
          "title" : "청산별곡",
          "note" : "살어리 살어리랏다 靑山에 살어리랏다. 멀위랑 달래 먹고 靑山에 살어리랏다.얄리얄리 얄랑셩 얄라리 얄라"
        }
      },
~~~~ 생략함 ~~~~~

“total” : “value” : 5, 로 잘 들어간것으로 나옵니다.

한글 검색해보기

이제부터 한글을 검색해봅시다. 여러가지 쿼리가 있고 검색 방법이 있지만 다음 쿼리를 통해 검색해봅시다. 검색할 필드를 지정해주고 query에 검색어를 넣어줍니다. 해당하는 단어가 찾아지게 하기 위해서 *(wildcard)를 넣어주었습니다. 뿐만 아니라 AND 와 OR를 지원하여 상세히 검색할 수 있씁니다.

GET my_index/_search
{
  "query": {
    "query_string": {
      "fields": ["title","note"],
      "query": "*얄리*"
    }
  }
}
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "Dt4MH20BjjMy29Rvz-kp",
        "_score" : 1.0,
        "_source" : {
          "title" : "청산별곡",
          "note" : "살어리 살어리랏다 靑山에 살어리랏다. 멀위랑 달래 먹고 靑山에 살어리랏다.얄리얄리 얄랑셩 얄라리 얄라"
        }
      }
    ]
  }
}

여담이지만 -_- 요구 스팩에 맞춰서 서비스를 이렇게 만들었는데 별로 안빠른거 같에서 고민이 많아집니다. query_string 말고 match_all 등의 쿼리를 참조하면 좀더 빠른 검색이 가능할 것 같습니다.

(참고: https://www.elastic.co/guide/en/elasticsearch/reference/7.3/search.html )

오늘은 여기까지…..

Elasticsearch 7.3 활용해보기 #4 – 기본적인 쿼리 사용

DB라면 기본적인 CRUD를 만들어봅시다. Elasticsearch는 RestAPI 다루듯이 쿼리한다고 생각하면 접근이 쉽습니다. 실제로 http 프로토콜로도 쿼리가 가능해서 서버에서 cros 접근설정이 되어있다면, Javascript로도 충분히 컨트롤이 가능하지요..

RestAPI에서 데이터를 가져올때 GET, 추가할때 POST, 삭제할때 DELETE, 수정할때 PUT을 사용하는 것처럼 Elasticsearch에서도 동일하게 사용됩니다

Elasticsearch에서는 index가 DB의 역할을 함으로 데이터를 추가하기위해서는 먼저 정의해야합니다. mapping을 통해 특별한 구조를 줄수도 있고 #3에서 처럼 Analyzer를 추가하여 단어의 색인 방법을 추가할 수도 있습니다.

index 생성

index를 추가하는 방법은 간단합니다.

PUT my_index
{

}

Kibana console에서 HTTP메서드인 PUT으로 간단히 이름만 적어줘도 생성되게 됩니다.

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "my_index"
}

문서(Document) 추가하기

만들어진 index에 문서를 추가해보면, 다음과 같이 작성할 수 있습니다. 원래는 _doc대신에 type(mapping정보?? info?? )가 들어갔으나, 7.0 이후로는 무형식API로 _doc로만 적어준다고합니다. ( https://www.elastic.co/kr/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0 )

POST my_index/_doc
{
  "name":"안주성",
  "age":"21",
  "gender":"남자"
}

추가된 결과는 다음처럼 나타납니다. _id는 특별히 부여하지 않았기 때문에 랜덤형식으로 나타나게 됩니다. _id를 지정하게 된다면 my_index/_doc/1 처럼 지정할 수 있습니다. _id는 문서를 컨트롤하는데 사용되게 됩니다.

{
  "_index" : "my_index",
  "_type" : "_doc",
  "_id" : "VtJO8mwBjjMy29RvFDdO",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

문서를 리스트로 불러오기

추가된 문서를 확인하기 위해서는 GET메서드를 사용합니다. _search로 호출되게 되며, 여러가지 검색조건을 덧붙일 수도 있습니다.(추후에 자세히 … 지금은 연습니니깐 -_- )

GET my_index/_search
{
  
}

응답은 다음과 같습니다. 불러다 쓸때는 hits.hits._source로 접근하여 실제 데이터를 가져다 쓸수있습니다.

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "VtJO8mwBjjMy29RvFDdO",
        "_score" : 1.0,
        "_source" : {
          "name" : "안주성",
          "age" : "21",
          "gender" : "남자"
        }
      }
    ]
  }
}

하나의 문서 불러오기

이번에는 하나의 문서만 호출해봅시다. 하나의 문서를 호출하기 위해서는 _id를 알고 있어야합니다. 다음같이 쿼리해봅니다. (주의할점은 여기에 {}를 주면 PUT 도 아닌데 문서가 갱신되게 되더군요 )

GET my_index/_doc/VtJO8mwBjjMy29RvFDdO

그러면 결과는… 해당 문서의 _source로 접근해 데이터를 가져올 수 있습니다.

{
  "_index" : "my_index",
  "_type" : "_doc",
  "_id" : "VtJO8mwBjjMy29RvFDdO",
  "_version" : 1,
  "_seq_no" : 3,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "안주성",
    "age" : "21",
    "gender" : "남자"
  }
}

문서의 갱신

문서를 갱신해봅시다. 문서갱신은 index생성과 마찬가지로 PUT메서드를 사용합니다. 다른점은 _id가 호출 주소에 덧붙여져 있습니다.

PUT my_index/_doc/VtJO8mwBjjMy29RvFDdO
{
  "name" : "안주섬",
  "age" : "39",
  "gender" : "남자"
}

정상적으로 갱신되었다면… _version이 증가하고 성공 메시지를 볼수 있습니다.

{
  "_index" : "my_index",
  "_type" : "_doc",
  "_id" : "VtJO8mwBjjMy29RvFDdO",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

다시 GET으로 확인해보면.. 데이터가 갱신 된것을 확인할 수 있습니다.

{
  "_index" : "my_index",
  "_type" : "_doc",
  "_id" : "VtJO8mwBjjMy29RvFDdO",
  "_version" : 2,
  "_seq_no" : 3,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "안주섬",
    "age" : "39",
    "gender" : "남자"
  }
}

문서의 삭제

문서의 조회와 유사하게 DELETE메서드를 통해 문서를 삭제할 수 있습니다.

DELETE my_index/_doc/VtJO8mwBjjMy29RvFDdO

잘 삭제되었다면,

{
  "_index" : "my_index",
  "_type" : "_doc",
  "_id" : "VtJO8mwBjjMy29RvFDdO",
  "_version" : 3,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 5,
  "_primary_term" : 1
}

다시 GET으로 해당 ID를 확인해보면.. 찾을 수 없다고 나옵니다. ㅎ

{
  "_index" : "my_index",
  "_type" : "_doc",
  "_id" : "VtJO8mwBjjMy29RvFDdO",
  "found" : false
}

index 삭제

index도 삭제해봅시다.

DELETE my_index

정말 간단하게 삭제되는군요….

{
  "acknowledged" : true
}

여기까지 입니다. -ㅅ-) …

다음에는 index/_search 의 상세조건알 알아봐야겠네요…

Elasticsearch 7.3 활용해보기 #3 – 사용자 색인작업(한글!)

생각해보니 이 앞전에 해보았던 자연어 처리기를 활용하여 인덱스에 세팅해보니 뭔가가 부족함이 있어 보입니다. 무슨 말이냐면, 붙어있는 단어들을 처리하지 못해서 mysql 에서의 field like ‘%이장님%’ 과 같은 단어를 처리하지 못하였습니다.

그래서 인덱스 생성시에 tokenizer 등을 추가적으로 지정해줄 필요가 있습니다. -_-

#2 에서 봤던 기본 분석기로는 세팅을 바꿀 수가 없어서 분석기가 포함된 인덱스를 만들어봅시다. 간단한 테스트를 할 때는 kibana의 console을 통해서 할 수 있습니다.

사용된 코드는 다음과 같습니다. 이렇게하면 korean_dict 인덱스가 생성되며, 이 인덱스의 설정에 따라 인덱스에 추가되는 문서들이 분석되게 됩니다. (원래 하고자하는 테스트도 할수 있습니다. -_-) 한글을 인덱스 만들때 쓸수 있음으로 아래의 세팅 내용은 잘 기억해둬야 될거 같습니다. (그러기엔 좀 길지만;;; 복사해서… … )

PUT korean_dict
{
  "settings":{
      "number_of_shards":1,
      "number_of_replicas":0,
      "index":{
        "analysis":{
          "tokenizer":{
            "nori_tokenizer_mixed_dict":{
              "type":"nori_tokenizer",
              "decompound_mode":"mixed",
              "user_dictionary":"userdict_ko.txt"
            }
          },
          "analyzer": {
            "korean":{
              "type":"custom",
              "tokenizer":"nori_tokenizer_mixed_dict",
              "filter":[
                "nori_readingform","lowercase",
                "nori_part_of_speech_basic"]
              }
            },
            "filter":{
              "nori_part_of_speech_basic":{
                "type":"nori_part_of_speech",
                "stoptags":["E","IC","J","MAG","MAJ","MM","SP","SSC","SSO","SC","SE","XPN","XSA","XSN","XSV","UNA","NA","VSV"]
            }
          }
        }
      }
    }
}

여기서 userdict_ko.txt 파일이 있습니다. 기본적인 nori 기능 이외에 추가적인 필터들 nori_readingform, nori_part_of _speech_basic 등을 추가하고 사용자 사전도 추가되었습니다.

사용자 사전은 다음 경로에 있습니다.

/etc/elasticsearch/userdict_ko.txt

사용자 사전의 용도는 인덱싱을 위해 잘라지지 않는 단어들에 대한 분리를 정의 할 수 있습니다. 전체 단어와 그 단어가 잘라진 모양을 기록해두면 됩니다.

고양이톱밥 고양이 톱밥
한글형태소분석기 한글 형태소 분석기
대한민국임시정부수립기념일 대한민국 임시정부 수립 기념일
우리동내 우리 동내

..... 등등 단어의 확장으로 ... 
도스르다 무슨 일을 하려고 벌려서 마음을 가다듬다(X 이건안됨)

반드시 해당하는 단어가 분리된 형태여야만 합니다.
(다른걸 집어 넣었떠니 오류가 -_-… )

뭐 어쨌뜬 이렇게해서 다시 토큰 분석 쿼리를 날려보면..

GET korean_dict/_analyze
{
  "analyzer": "korean",
  "text": "대한민국임시정부수립기념일"
}

단어분리가 사전에 정의한 단어를 포함하여 파싱되는 것을 확인 할 수 있습니다.

{
  "tokens" : [
    {
      "token" : "대한민국",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "word",
      "position" : 0,
      "positionLength" : 2
    },
    {
      "token" : "대한",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "민국",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "임시",
      "start_offset" : 4,
      "end_offset" : 6,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "정부",
      "start_offset" : 6,
      "end_offset" : 8,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "수립",
      "start_offset" : 8,
      "end_offset" : 10,
      "type" : "word",
      "position" : 4
    },
    {
      "token" : "기념일",
      "start_offset" : 10,
      "end_offset" : 13,
      "type" : "word",
      "position" : 5,
      "positionLength" : 2
    },
    {
      "token" : "기념",
      "start_offset" : 10,
      "end_offset" : 12,
      "type" : "word",
      "position" : 5
    },
    {
      "token" : "일",
      "start_offset" : 12,
      "end_offset" : 13,
      "type" : "word",
      "position" : 6
    }
  ]
}

그렇다면 원래 분석기는 사용자 사전에 해당하는 단어가 검색되지 않습니다.
(#2에 사용된 쿼리를 이용하였습니다.)

{
  "tokens" : [
    {
      "token" : "대한",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "민국",
      "start_offset" : 2,
      "end_offset" : 4,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "임시",
      "start_offset" : 4,
      "end_offset" : 6,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "정부",
      "start_offset" : 6,
      "end_offset" : 8,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "수립",
      "start_offset" : 8,
      "end_offset" : 10,
      "type" : "word",
      "position" : 4
    },
    {
      "token" : "기념",
      "start_offset" : 10,
      "end_offset" : 12,
      "type" : "word",
      "position" : 5
    },
    {
      "token" : "일",
      "start_offset" : 12,
      "end_offset" : 13,
      "type" : "word",
      "position" : 6
    }
  ]
}

만약에 실무에 활용한다면, 사용자 사전에 단어를 추가하여 검색되지 않는 단어를 대응 하면 되지 않을까요!

오늘도 여기까지 -_- …

꾸준히 계속 적어봐야겠네요…