본문 바로가기

데이터베이스/ELK

[ELK] Elasticsearch 한글 형태소 분석기 nori tokenizer

1. nori tokenizer의 필요성

ES의 기존의 형태소 분석기는 한글을 토큰으로 분리하는데 적합하지가 않다. 한글은 제대로 구현이 되어있지 않기 때문이다.

그래서 새롭게 나온 분석기가 한글 형태소 분석기 즉, nori tokenizer이다.

 

 

2. analysis-nori 플러그인 설치

ES 버전은 7.16.4를 사용하였고, 로컬 docker 환경에서 구축하였다.

# elasticsearch/Dockerfile

FROM elasticsearch:7.16.3
RUN bin/elasticsearch-plugin install --batch analysis-nori

ES의 Dockerfile에 노리 플러그인을 RUN 명령어로 추가하면 ES 컨테이너가 생성되면서 노리 플러그인도 같이 설치가 된다.

 

 

3. Standard Tokenizer VS Nori Tokenizer 차이점

###################### Nori Tokenizer 테스트 #################################

GET _analyze
{
  "tokenizer": "standard",
  "text" : [
      "개발자 츄르 입니다"
    ]
}

# 실행 결과
{
  "tokens" : [
    {
      "token" : "개발자",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "<HANGUL>",
      "position" : 0
    },
    {
      "token" : "츄르",
      "start_offset" : 4,
      "end_offset" : 7,
      "type" : "<HANGUL>",
      "position" : 1
    },
    {
      "token" : "입니다",
      "start_offset" : 8,
      "end_offset" : 11,
      "type" : "<HANGUL>",
      "position" : 2
    }
  ]
}



GET _analyze
{
  "tokenizer": "nori_tokenizer",
  "text" : [
      "개발자 츄르 입니다"
    ]
}
# 실행 결과 
{
  "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" : 4,
      "end_offset" : 7,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "이",
      "start_offset" : 8,
      "end_offset" : 11,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "ᄇ니다",
      "start_offset" : 8,
      "end_offset" : 11,
      "type" : "word",
      "position" : 4
    }
  ]
}

Standard Tokenizer는 한글을 대상으로 공백 외에는 아무런 단어에 대해 분리하지 못한다는 것을 확인할 수 있다.

반면에, Nori Tokenizer는 한국어 사전 정보를 이용해 품사와 같은 단어들을 분리해줄 수 있다.

 

 

4. 인덱스에 한글 형태소 분석기 적용

PUT elk-test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "nori": {
          "tokenizer": "nori_tokenizer"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "message.title": {
        "type": "text",
        "analyzer": "nori"
      },
      "message.content": {
        "type": "text",
        "analyzer": "nori"
      }
    }
  }
}

인덱스이름은 "elk-test"로 하고, nori_tokenizer를 애널라이저로 설정한다.

또한, mappings을 message의 title과 content를 text 타입과 settings에서 nori로 설정한 값을 적용시켰다.

 

 

5. 동작 확인

먼저, 위에서 생성한 인덱스에 데이터를 삽입해야한다.

###### 데이터 도큐먼트 생성 ######

POST elk-test/_doc/
{
  "message": {
    "Article_id": "a4847333-c581-409c-b9a8-asdasd",
    "title": "동해물과 백두산이",
    "content": "애국가입니다.",
    "Board_id": "532aa49c-c677-4fe6-8a93-asdasdasd",
    "Message": "Article Create"
  }
}

message라는 필드에서 여러 데이터를 json 형태로 ES에 저장했다.

 

###### 검색 ######

GET elk-test/_search
{
  "query":
  {
    "match": {
      "message.title": "동해물"
    }
  }
}

_search API를 이용해서 인덱스 검색 쿼리를 실행시킨다.

match 타입을 이용해서 message 필드 안에 title 타입에서 "동해물"이라는 단어를 검색한다.

 

##### 결과 #####

{
  "took" : 15,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "elk-test",
        "_type" : "_doc",
        "_id" : "HsX2MIUBf_9zws4XWNc-",
        "_score" : 0.5753642,
        "_source" : {
          "message" : {
            "Article_id" : "a4847333-c581-409c-b9a8-asdasd",
            "title" : "동해물과 백두산이",
            "content" : "애국가입니다.",
            "Board_id" : "532aa49c-c677-4fe6-8a93-asdasdasd",
            "Message" : "Article Create"
          }
        }
      }
    ]
  }
}

위와 같이 검색이 잘 되는 것을 확인할 수 있다.