기존에 만들어 놓은 인덱스 중 필드 하나에 analyzer 를 추가하고 싶었다.
한글 형태 검색이 필요했기 때문이다.
그러나 기존에 만들어진 맵핑된 필드라면 변경이 힘들다.
그 과정을 정리해보려고 한다.
목표 : 기존 tb_schoolbasicinformation-develop 이라는 인덱스에서 schul_nm 이라는 필드에 analyzer 를 추가하려고 한다.
1. 맵핑 조회
GET tb_schoolbasicinformation-develop/_mapping
결과 (AS-IS) :
... 중략 "schul_nm" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, 중략 ...
(TO-BE) 이 상태에서 내가 원하는 것은 아래와 같은 모습이다.
... 중략 "schul_nm" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } }, "fielddata": true, "analyzer": "korean" }, 중략 ...
위처럼 analyzer 에 korean 을 추가하는 것이다.
물론 korean 역시 tb_schoolbasicinformation-develop 인덱스 자체에 설정을 우선 할 예정이다.
2. 인덱스에 analyzer 추가를 위해 tb_schoolbasicinformation-develop 인덱스 셋팅 조회
GET tb_schoolbasicinformation-develop/_settings
결과 :
{ "tb_schoolbasicinformation-develop" : { "settings" : { "index" : { "creation_date" : "1707991821167", "number_of_shards" : "5", "number_of_replicas" : "1", "uuid" : "SADFSDFDASFDSAF", "version" : { "created" : "7100299" }, "provided_name" : "tb_schoolbasicinformation-develop" } } } }
3. 인덱스에 analyzer 추가
PUT tb_schoolbasicinformation-develop/_settings { "analysis": { "filter": { "edge_ngram": { "type": "edge_ngram", "min_gram": 1, "max_gram": 2, "token_chars": ["letter", "digit"] } }, "tokenizer" : { "seunjeon" : { "type" : "seunjeon_tokenizer", "index_eojeol": false, "index_poses": ["UNK","EP","I","J","M","N","SL","SH","SN","VCP","XP","XS","XR"], "decompound": true } }, "analyzer": { "korean": { "type": "custom", "tokenizer": "seunjeon", "filter": [ "edge_ngram" ] } } } }
플러그인 은전한잎으로 tokenizer 설정하여 analyzer 에 korean을 추가하였고,
filter에 edge_ngram 을 설정하였다.
이 edge_ngram 필터는 analysis 아래 filter 에 추가해 놓은 필터이다.
이 상태로 실행하면 아래와 같은 오류가 난다.
{ "error" : { "root_cause" : [ { "type" : "illegal_argument_exception", "reason" : "Can't update non dynamic settings [[index.analysis.analyzer.korean.tokenizer, index.analysis.filter.edge_ngram.min_gram, index.analysis.tokenizer.seunjeon.type, index.analysis.filter.edge_ngram.token_chars, index.analysis.tokenizer.seunjeon.decompound, index.analysis.analyzer.korean.filter, index.analysis.filter.edge_ngram.max_gram, index.analysis.analyzer.korean.type, index.analysis.tokenizer.seunjeon.index_eojeol, index.analysis.tokenizer.seunjeon.index_poses, index.analysis.filter.edge_ngram.type]] for open indices [[tb_schoolbasicinformation-develop/asdf]]" } ], "type" : "illegal_argument_exception", "reason" : "Can't update non dynamic settings [[index.analysis.analyzer.korean.tokenizer, index.analysis.filter.edge_ngram.min_gram, index.analysis.tokenizer.seunjeon.type, index.analysis.filter.edge_ngram.token_chars, index.analysis.tokenizer.seunjeon.decompound, index.analysis.analyzer.korean.filter, index.analysis.filter.edge_ngram.max_gram, index.analysis.analyzer.korean.type, index.analysis.tokenizer.seunjeon.index_eojeol, index.analysis.tokenizer.seunjeon.index_poses, index.analysis.filter.edge_ngram.type]] for open indices [[tb_schoolbasicinformation-develop/asdf]]" }, "status" : 400 }
4. 설정을 하기 위해서 해당 인덱스를 닫는다.
POST tb_schoolbasicinformation-develop/_close
위처럼 tb_schoolbasicinformation-develop 인덱스를 닫아준다.
결과 :
{ "acknowledged" : true, "shards_acknowledged" : true, "indices" : { "tb_schoolbasicinformation-develop" : { "closed" : true } } }
정상적으로 닫아졌다고 나온다.
이제 다시 3번의 'PUT tb_schoolbasicinformation-develop/_settings' 을 실행하면 아래와 같이 정상 추가되어 결과값이 노출된다.
결과 :
{ "acknowledged" : true }
정상적으로 처리되었다는 결과 코드다.
5. 설정이 끝났으니 다시 인덱스를 연다.
POST tb_schoolbasicinformation-develop/_open
결과 :
{ "acknowledged" : true, "shards_acknowledged" : true }
위와 같이 정상적으로 열렸다고 나온다.
6. 이제 1번에서 진행하려 했던 TO-BE 작업인 "analyzer": "korean" 를 추가하는 작업이다.
먼저 매핑을 수정해보자.
PUT tb_schoolbasicinformation-develop/_mapping { "properties": { "schul_nm": { "type": "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } }, "fielddata": true, "analyzer": "korean" } } }
결과 :
{ "error" : { "root_cause" : [ { "type" : "illegal_argument_exception", "reason" : "Mapper for [schul_nm] conflicts with existing mapper:\n\tCannot update parameter [analyzer] from [default] to [korean]" } ], "type" : "illegal_argument_exception", "reason" : "Mapper for [schul_nm] conflicts with existing mapper:\n\tCannot update parameter [analyzer] from [default] to [korean]" }, "status" : 400 }
이렇게 오류가 난다.
이유는 기존에 만들어져 있는 맵핑 필드인 schul_nm 을 수정할 수 없는 것이다.
그렇기 때문에 편법을 사용해야 하는 상황인데,
빈 인덱스 B를 하나 만들고 거기에 미리 analysis 셋팅 값 설정과 맵핑 필드 바꾸려 했던 매핑 설정을 미리 해 놓고 원본 인덱스 A를 새로 만든 빈 인덱스 B로 리인덱스 한다.
(복사 붙여넣기라 생각 하면 됨)
그리고 원본 인덱스인 A를 지우고 리인덱스한 B를 다시 A라는 이름으로 리인덱스한다. ( 또 복사 붙여넣기를 한 것이다.)
그러면 A, B 인덱스가 존재하고 양쪽다 우리가 지금까지 바꾸려고 했던 값들로 설정된 것이다.
이제 필요없는 B 인덱스를 지우면 끝이다.
간략 요약하자면,
A-1. B 라는 빈 인덱스 생성
A-2. B 인덱스에 analysis 셋팅, 맵핑 설정
A-3. A 에서 B로 리인덱스
A-4. A 인덱스 삭제
A-5. B 에서 A로 리인덱스
A-6. B 인덱스 삭제
그 과정을 이제 예시로 보자.
7. 빈 인덱스를 하나 생성한다. (A-1)
PUT tb_schoolbasicinformation-develop2
정상적으로 생성되었다면 아래처럼 결과 노출된다.
{ "acknowledged" : true, "shards_acknowledged" : true, "index" : "tb_schoolbasicinformation-develop2" }
8. analysis 셋팅을 하고 맵핑 설정도 하고 리인덱스 하는 (A-2 ~ A-3) 과정을 아래처럼 진행한다.
POST tb_schoolbasicinformation-develop2/_close PUT tb_schoolbasicinformation-develop2/_settings { "analysis": { "filter": { "edge_ngram": { "type": "edge_ngram", "min_gram": 1, "max_gram": 10, "token_chars": ["letter", "digit"] } }, "tokenizer" : { "seunjeon" : { "type" : "seunjeon_tokenizer", "index_eojeol": false, "index_poses": ["UNK","EP","I","J","M","N","SL","SH","SN","VCP","XP","XS","XR"], "decompound": true } }, "analyzer": { "korean": { "type": "custom", "tokenizer": "seunjeon", "filter": [ ] } } } } POST tb_schoolbasicinformation-develop2/_open PUT tb_schoolbasicinformation-develop2/_mapping { "properties": { "schul_nm": { "type": "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } }, "fielddata": true, "analyzer": "korean" } } } POST _reindex { "source": { "index": "tb_schoolbasicinformation-develop" }, "dest": { "index": "tb_schoolbasicinformation-develop2" } }
결과가 정상적으로 처리되었다면 아래처럼 나온다.
{ "took" : 10022, "timed_out" : false, "total" : 13388, "updated" : 0, "created" : 13388, "deleted" : 0, "batches" : 14, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] }
한번 제대로 적용되었는 지 확인해보자.
GET tb_schoolbasicinformation-develop2/_mapping
"schul_nm" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } }, "analyzer" : "korean", "fielddata" : true }
내용 중에 "analyzer": "korean" 을 정상적으로 들어가 있음을 확인하였다.
9. 이제 원본 인덱스를 삭제해 준다. (A-4)
DELETE tb_schoolbasicinformation-develop
{ "acknowledged" : true }
정상적으로 처리되었다.
10. 다시 tb_schoolbasicinformation-develop2 를 tb_schoolbasicinformation-develop 로 리인덱스 해주어 tb_schoolbasicinformation-develop 에도 tb_schoolbasicinformation-develop2의 설정과 내용들이 다 들어가 있게 해준다. (A-5)
POST _reindex { "source": { "index": "tb_schoolbasicinformation-develop2" }, "dest": { "index": "tb_schoolbasicinformation-develop" } }
{ "took" : 7915, "timed_out" : false, "total" : 13388, "updated" : 0, "created" : 13388, "deleted" : 0, "batches" : 14, "version_conflicts" : 0, "noops" : 0, "retries" : { "bulk" : 0, "search" : 0 }, "throttled_millis" : 0, "requests_per_second" : -1.0, "throttled_until_millis" : 0, "failures" : [ ] }
total 값을 보니 모두 정상적으로 리인덱스 되었다.
11. 이제 불필요해진 인덱스 tb_schoolbasicinformation-develop2 를 지워준다. (A-6)
DELETE tb_schoolbasicinformation-develop2
{ "acknowledged" : true }
이제 남은 인덱스는 tb_schoolbasicinformation-develop 이고 _settings 또는 _mapping 으로 조회하면 내가 바꾸려 했던 대로 잘 바뀌어져 있음을 확인할 수 있다.