Elasticsearch filter에서 한자로 검색했을 때 일치하는 한글 결과로 tokenizing하게 해주는 filter가 있다. 해당 filter는 nori-readingform이다. 적용 방법은 기존에 synonmys나 speech필터 적용과 동일하다.

 

인덱스 생성


위에서 부터 사용했던 인덱스에 nori_readingform 필터를 추가해서 생성만 해주면 된다.

PUT wedul_anaylyzer
{
  "settings": {
    "index" : {
      "analysis" : {
        "tokenizer": {
          "nori_user_dict": {
            "type": "nori_tokenizer",
            "decompound_mode": "none",
            "user_dictionary": "dic/nori_userdict_ko.txt"
          }
        },
        "analyzer" : {
          "custom_analyze" : {
            "type": "custom",
            "tokenizer" : "nori_user_dict",
            "filter": [
              "my_posfilter",
              "nori_readingform"
            ]
          }
        },
        "filter": {
          "my_posfilter": {
            "type": "nori_part_of_speech",
            "stoptags": [
              "NP", "UNKNOWN"
            ]
          }
        }
      }
    }
  }
}

이렇게 만든 인덱스를 이용해서 한자를 이용해서 한글 내용을 뽑아내보자

결과


행복이라는 한자를 입력하여 검색해보자. 필터가 정상적으로 적용된다면 행복이라는 내용을 가진 결과가 나올것이다

GET wedul_analyzer/_analyze
{
"analyzer": "custom_analyze",
"text": "幸福 사랑"
}

결과는 정상적으로 행복 그리고 사랑이라는 단어로 추출되었다. nori를 공부하면서 좋은 기본 필터 많은걸 알게 되서 좋다.

elasticsearch에서 검색기능을 넣다가 2080이라는 키워드를 검색 했을때와 이공팔공이라는 검색어를 입력했을 때 두개 모두 동일한 데이터를 출력하도록 지정하고 싶었다.

그래서 synonyms 필터를 만들기로 했다.

우선 synonyms 필터를 만들어서 사용하기 위해서는 동의어에 대한 정리가 되어있는 사전을 만들어야 한다.

사전 생성 방법은 다음과 같고 아래 링크를 참조해서 간단하게 사전을 만들었다.
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-synonym-tokenfilter.html

파일명은 synonyms.txt이고 내용은 다음과 같다.

synonyms.txt

노레바,noreva,노래바
airpods,에어팟,airpod,airpot
2080,이공팔공

 

동의어 정리 사전을 elasticsearch에 넣어줘야하고 경로는 다음과 같다.

/usr/share/elasticsearch/config/analysis



나는 docker를 사용하기 때문에 생성한 파일을 다음 명령어를 통해 위치시켰다.

docker cp synonyms.txt elastic6.4:/usr/share/elasticsearch/config/analysis



그럼 이 필터를 사용하기 위해서 인덱스를 만들 때 설정을 달아서 추가해주자.
간단하게 keyword 하나만 존재하는 인덱스를 만들고 synonyms filter를 사용하게 해보자

여기서 사용하 tokenizer는 nori_tokenizer를 사용했다.
간단한 예제니 보면 바로 이해할 수 있다.

PUT synonyms_test
{
  "settings": {
      "index" : {
          "analysis" : {
              "analyzer" : {
                  "synonym" : {
                      "tokenizer" : "nori_tokenizer",
                      "filter" : ["synonym"]
                  }
              },
              "filter" : {
                  "synonym" : {
                      "type" : "synonym",
                      "synonyms_path" : "analysis/synonyms.txt"
                  }
              }
          }
      }
  },
  "mappings": {
    "_doc": {
      "dynamic": "false",
      "properties": {
        "keyword": {
          "type": "text",
          "analyzer": "synonym",
          "search_analyzer": "synonym",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

데이터를 2080과 이공팔공 두개를 삽입했다.

POST synonyms_test/_doc
{
  "keyword":"2080"
}

POST synonyms_test/_doc
{
  "keyword":"이공팔공"
}

그럼 이 두개의 키워드가 동일하게 하나의 명령어로 검색이 되는지 확인해보자.

GET synonyms_test/_search
{
  "query": {
    "match": {
      "keyword": "이공팔공"
    }
  }
}

2080과 이공팔공으로 검색한 결과

엘라스틱 서치를 쓰면서 기존에 형태소 분석기를 아리랑, 은전한닢, open korea등을 사용했었다.


근데 이번에 6.4버전이 출시 되면서 Elasticsearch에서 기본으로 제공하는 한글 형태소 분석기가 나왔다. 이름은 nori(노리)이다. 

노리는 놀이라는 뜻에서 가져왔으며 mecab-ko-dic 사전을 이용하지만 사전을 압축하므로 기존 형태소 분석기와 비교하여 메모리를 적게 쓰고 훨씬 빠르다.


그럼 Docker에 엘라스틱서치 6.4와 Kibana 6.4를 설치하고 Nori 플러그인을 설치해서 한글 형태소분석기를 사용해보자.


Docker에 Elasticsearch와 Kibana 설치

1
2
docker run --9200:9200 -9300:9300 --name elastic -"discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:6.4.0
docker run ---link elastic:elastic-url -"ELASTICSEARCH_URL=http://elastic-url:9200" -5601:5601 --name kibana docker.elastic.co/kibana/kibana:6.4.0
cs

설치를 완료하고 docker process를 확인하여 정상 동작하는지 확인한다.



Elasticsearch에 Nori 플러그인 설치

엘라스틱서치 bash셀에 접근해서 anaysis-nori를 설치한다.

1
2
3
4
5
6
// elasticsearch의 bash셀 접근
docker exec -it elastic /bin/bash
 
 
// 노리 플러그인 설치
bin/elasticsearch-plugin install analysis-nori
cs


설치가 완료되면 elasticsearch 프로세스를 재 시작 한다. 그러면서 프로세스가 올라올때 Nori 플러그인이 정상적으로 올라오는지 확인해보자.

1
[2018-10-13T01:26:05,498][INFO ][o.e.p.PluginsService     ] [dFC4eSy] loaded plugin [analysis-nori]
cs


그리고 Kibana를 사용해서 분석 플러그인 동작을 확인하자

1
2
3
4
5
6
7
GET _analyze
{
  "analyzer": "nori",
  "text" : "안녕 나는 바보 위들이야."
}
 
 
cs




사전 추가하기

위에 결과를 보면 위들이라는건 하나의 대명사로써 내 별칭인데 '들'이라는 조사를 제거하고 보여주느라 위들이라는 단어가 사라졌다. 이를 해결하기위해 사전을 만들어서 위들을 추가해보자.


먼저 사전에 사용될 사전은 mecab-ko-dic을 사용한다. 플러그인 설치했던것처럼 Elasticsearch에 접속하여 config/userdict_ko.txt를 생성한다. 그리고 그 txtx파일에 "위들"을 추가한다.


그리고 해당 사전을 사용하도록 anaylzer를 생성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PUT nori_sample
{
  "settings": {
    "index": {
      "analysis": {
        "tokenizer": {
          "nori_user_dict": {
            "type": "nori_tokenizer",
            "decompound_mode": "mixed",
            "user_dictionary": "userdict_ko.txt"
          }
        },
        "analyzer": {
          "my_analyzer": {
            "type": "custom",
            "tokenizer": "nori_user_dict"
          }
        }
      }
    }
  }
}
cs


그리고 다시한번 조회해보자.

1
2
3
4
5
6
GET nori_sample/_analyze
{
  "analyzer": "my_analyzer",
  "text" : "안녕 나는 바보 위들이야."
}
 
cs

결과를 확인해보면 정상적으로 위들이 형태소분석기에 의해 잘 나누어지는 것을 볼 수 있다.


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{
  "tokens": [
    {
      "token": "안녕",
      "start_offset": 0,
      "end_offset": 2,
      "type": "word",
      "position": 0
    },
    {
      "token": "나",
      "start_offset": 3,
      "end_offset": 4,
      "type": "word",
      "position": 1
    },
    {
      "token": "는",
      "start_offset": 4,
      "end_offset": 5,
      "type": "word",
      "position": 2
    },
    {
      "token": "바보",
      "start_offset": 6,
      "end_offset": 8,
      "type": "word",
      "position": 3
    },
    {
      "token": "위들",
      "start_offset": 9,
      "end_offset": 11,
      "type": "word",
      "position": 4
    },
    {
      "token": "이",
      "start_offset": 11,
      "end_offset": 12,
      "type": "word",
      "position": 5
    },
    {
      "token": "야",
      "start_offset": 12,
      "end_offset": 13,
      "type": "word",
      "position": 6
    }
  ]
}
cs



참고

https://www.elastic.co/guide/en/elasticsearch/plugins/6.4/analysis-nori.html

https://www.elastic.co/kr/blog/nori-the-official-elasticsearch-plugin-for-korean-language-analysis

https://www.elastic.co/guide/en/elasticsearch/plugins/6.4/analysis-nori-tokenizer.html

+ Recent posts