본문 바로가기
Elasticsearch

Elasticsearch + nori 한글 형태소 분석기로 데이터 검색하기 # 1

by reo.l 2021. 8. 27.

 

nori 토크 나이저 적용 전  간단한 예를 들어 nori  토크 나이저에 대하여 설명하겠다.

( 참고 : https://esbook.kimjmin.net/06-text-analysis/6.7-stemming/6.7.2-nori )

elasticsearch에서 제공하는 standard 토크 나이저 사용 시 다음과 같이 단순히 띄어쓰기에 대한 결과를 보여준다.

 

standard 토크나이저로 "동해물과 백두산이" 문장 분석
GET _analyze
{
  "tokenizer": "standard",
  "text": [
    "동해물과 백두산이"
  ]
}

standard 토크나이저로 "동해물과 백두산이" 문장 분석 결과
{
  "tokens" : [
    {
      "token" : "동해물과",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "<HANGUL>",
      "position" : 0
    },
    {
      "token" : "백두산이",
      "start_offset" : 5,
      "end_offset" : 9,
      "type" : "<HANGUL>",
      "position" : 1
    }
  ]
}

 

그러나 nori 토크 나이저를 적용하면 좀 더 세분화된 검색 결과를 만들어 낼 수 있다.

 

nori_tokenizer 토크나이저로 "동해물과 백두산이" 문장 분석
GET _analyze
{
  "tokenizer": "nori_tokenizer",
  "text": [
    "동해물과 백두산이"
  ]
}

nori_tokenizer 토크나이저로 "동해물과 백두산이" 문장 분석 결과
{
  "tokens" : [
    {
      "token" : "동해",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "물",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "과",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "백두",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "산",
      "start_offset" : 7,
      "end_offset" : 8,
      "type" : "word",
      "position" : 4
    },
    {
      "token" : "이",
      "start_offset" : 8,
      "end_offset" : 9,
      "type" : "word",
      "position" : 5
    }
  ]
}

 

다음은 nori에서 제공하는 옵션들인데 이것을 이용해 좀더 세분화된 검색이 가능하다.

 

  • user_dictionary : 사용자 사전이 저장된 파일의 경로를 입력합니다.
  • user_dictionary_rules : 사용자 정의 사전을 배열로 입력합니다.
  • nori_part_of_speech : 제거할 품사 정보 지정합니다.
  • decompound_mode : 합성어의 저장 방식을 결정합니다. 다음 3개의 값을 사용 가능합니다.
    • none : 어근을 분리하지 않고 완성된 합성어만 저장합니다.
    • discard (디폴트) : 합성어를 분리하여 각 어근만 저장합니다.
    • mixed : 어근과 합성어를 모두 저장합니다.

 

이글에서는 이 옵션들 중 nori_part_of_speech, decompound_mode를 사용할것이다.

 

먼저 전에 설치한 elasticsearch plugin에 nori를 설치하여 준다.

 

$ bin/elasticsearch-plugin install analysis-nori

 

적용 순서는 template 파일을 만들어 nori 토크 나이저를 적용하고

logstash를 통해 elaticsearch index를 output 할 때 template파일을 같이 적용시킬 것이다.

/etc/logstash/partner_template.json 파일을 만들고 nori 토크 나이저, 옵션 등을 설정해준다.

 

/etc/logstash/partner_template.json

{   "template":"partner-*",
    "settings": {
        "index": {
            "analysis": {
                "analyzer": {
                    "my_analyzer": {
                        "type": "custom",
                        "tokenizer": "my_nori_tokenizer",
                        "filter" : [
                            "nori_posfilter"
                            ]
                    }
                },
                "tokenizer": {
                    "my_nori_tokenizer": {
                      "type": "nori_tokenizer",
                      "decompound_mode": "none"
                    }
                  },
                "filter": {
                    "nori_posfilter" : {
                      "type" : "nori_part_of_speech",
                      "stoptags": [
                        "E",
                        "IC",
                        "J",
                        "MAG", "MAJ", "MM",
                        "NA", "NR",
                        "SC", "SE", "SF", "SH", "SL", "SN", "SP",
                        "SSC", "SSO", "SY",
                        "UNA", "UNKNOWN",
                        "VA", "VCN", "VCP", "VSV",
                        "VV", "VX",
                        "XPN", "XR", "XSA", "XSN", "XSV"
                        ]
                    }
                  }
            }
        }
    },
    "mappings": {
            "properties": {
                "id": {
                    "type": "long"
                },
                "name": {
                    "type": "text",
                    "fields": {
                        "english_field": {
                            "type": "text",
                            "analyzer": "english"
                          },
                        "korean_field": {
                            "analyzer": "my_analyzer",
                            "type": "text"
                        }
                    }
                },
                "info_company": {
                    "type": "text",
                    "fields": {
                        "english_field": {
                            "type": "text",
                            "analyzer": "english"
                          },
                        "korean_field": {
                            "analyzer": "my_analyzer",
                            "type": "text"
                        }
                    }
                },
                "history": {
                    "type": "text",
                    "fields": {
                        "english_field": {
                            "type": "text",
                            "analyzer": "english"
                          },
                        "korean_field": {
                            "analyzer": "my_analyzer",
                            "type": "text"
                        }
                    }
                },
                "region": {
                    "type": "text",
                    "fields": {
                        "english_field": {
                            "type": "text",
                            "analyzer": "english"
                          },
                        "korean_field": {
                            "analyzer": "my_analyzer",
                            "type": "text"
                        }
                    }
                }
            }
    }
}

 

토크 나이저 선언 시 decompound_mode : none을 설정하였는데 default인 dicard는 어근을 분리하여 '선풍기' 검색 시에 '선풍', '기'로 각각 검색하기에 어근을 분리하지 않은 none으로 설정하였다.

nori 토크 나이저의 필터로는 nori_part_of_speech를 사용하였는데 이는 불필요한 품사를 제거해준다. 동사, 감탄사 등..

 

(출처 : 꼬꼬마 한국어 형태소 분석기 - http://kkma.snu.ac.kr/documents/?doc=postag)

 

mappings에서 property 마다 english_field와 korean_field를 나누어 주는 이유는 nori 토크 나이저 만 적용 시 영어 검색은 되지 않기 때문이다. 그래서 elasticsearch에서 제공하는 기본 english 토크 나이저를 같이 달아주었다.

 

이렇게 하면 elasticsearch index에 적용될 template 설정은 완료가 됐다. 다음 글에서 이를 logstash에 적용하고 직접 데이터를 넣고 django에서 데이터를 받아 사용하는 부분에 대하여 설명하겠다.

 

 

 

 

댓글