Elasticsearch에 있는 analyzer는 입력 문자열을 토큰 리스트로 변환해줍니다. 이는 역인덱스(Inverted Index)의 기능을 향상시키고 효과적인 검색을 이끕니다. Elasticsearch에는 다양한 built-in analyzer가 존재합니다. 이 글에서는 한국어 전용인 nori analyzer를 cURL 기반으로 실행하는 법을 알아보겠습니다.


먼저, 운영체제에 맞게 Elasticsearch를 다운로드한다.

압축 해제한 폴더에 들어가 다음 명령어로 Elasticsearch를 실행한다.

$ ./bin/elasticsearch

http://localhost:9200/에 접속 후 다음과 같은 화면으로 Elasticsearch가 정상적으로 실행됐는지 확인한다.

{
  "name" : "yskim.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "IQWi9ZCwQeunmmK19viypw",
  "version" : {
    "number" : "7.7.1",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "ad56dce891c901a492bb1ee393f12dfff473a423",
    "build_date" : "2020-05-28T16:30:01.040088Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

다음 curl 명령어를 통해 standard analyzer를 실행할 수 있다.

$ curl -X GET "localhost:9200/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
   "analyzer":"standard",
   "text":"자연어처리란????!"
}'
{
  "tokens" : [
    {
      "token" : "자연어처리란",
      "start_offset" : 0,
      "end_offset" : 6,
      "type" : "<HANGUL>",
      "position" : 0
    }
  ]
}

한국어 분석기 nori는 built-in이 아니므로 다음 명령어를 통해 플러그인으로 설치한다. 실행 중인 Elasticsearch를 종료하고 설치해야 한다.

$ ./bin/elasticsearch-plugin install analysis-nori
-> Installing analysis-nori
-> Downloading analysis-nori from elastic
[=================================================] 100%   
-> Installed analysis-nori

Elasticsearch를 재시작하고, 다음 curl을 통해 nori analyzer를 실행한다.

$ curl -X GET "localhost:9200/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
   "analyzer":"nori",
   "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" : 3,
      "end_offset" : 5,
      "type" : "word",
      "position" : 2
    }
  ]
}

다음 옵션으로 추가적인 토큰 정보를 확인할 수 있다.

$ curl -X GET "localhost:9200/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
   "analyzer":"nori",
   "text":"자연어처리란????!",
   "attributes":[
      "posType",
      "leftPOS",
      "rightPOS",
      "morphemes",
      "reading"
   ],
   "explain":true
}'
{
  "detail" : {
    "custom_analyzer" : false,
    "analyzer" : {
      "name" : "org.apache.lucene.analysis.ko.KoreanAnalyzer",
      "tokens" : [
        {
          "token" : "자연",
          "start_offset" : 0,
          "end_offset" : 2,
          "type" : "word",
          "position" : 0,
          "leftPOS" : "NNG(General Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "reading" : null,
          "rightPOS" : "NNG(General Noun)"
        },
        {
          "token" : "어",
          "start_offset" : 2,
          "end_offset" : 3,
          "type" : "word",
          "position" : 1,
          "leftPOS" : "NNG(General Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "reading" : null,
          "rightPOS" : "NNG(General Noun)"
        },
        {
          "token" : "처리",
          "start_offset" : 3,
          "end_offset" : 5,
          "type" : "word",
          "position" : 2,
          "leftPOS" : "NNG(General Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "reading" : null,
          "rightPOS" : "NNG(General Noun)"
        }
      ]
    }
  }
}

위의 테스트는 모두 nori의 디폴트 모드에서 실행된 결과이다. 우리의 입맛에 맞게 옵션을 설정하려면 다음과 같은 세팅으로 새로운 인덱스를 생성한다.

$ curl -X PUT "localhost:9200/my_nori?pretty" -H 'Content-Type: application/json' -d'
{
   "settings":{
      "index":{
         "analysis":{
            "analyzer":{
               "my_nori":{
                  "char_filter":[
                     "my_char_filter"
                  ],
                  "tokenizer":"my_nori_tokenizer",
                  "filter":[
                     "synonym_filter",
                     "pos_filter"
                  ]
               }
            },
            "char_filter":{
               "my_char_filter":{
                  "type":"mapping",
                  "mappings":[
                     "A => AAA"
                  ]
               }
            },
            "tokenizer":{
               "my_nori_tokenizer":{
                  "type":"nori_tokenizer",
                  "decompound_mode":"discard",
                  "user_dictionary_rules":[
                     "기계학습",
                     "자연어처리 자연어 처리"
                  ]
               }
            },
            "filter":{
               "pos_filter":{
                  "type":"nori_part_of_speech",
                  "stoptags":[
                     "SN"
                  ]
               },
               "synonym_filter":{
                  "type":"synonym_graph",
                  "synonyms":[
                     "기계학습, ML",
                     "자연어,natural language",
                     "처리,processing"
                  ]
               }
            }
         }
      }
   }
}'
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "my_nori"
}

Analyzer는 filter, tokenizer 등으로 구성되며 다양한 옵션을 제공한다. 이러한 옵션과 함께 노리에 대한 내용은 노리(Nori) 형태소 분석기 Deep Dive 블로그를 참고하길 바란다.

새로운 인덱스와 새롭게 세팅한 nori analyzer에 curl을 날리면 다음과 같은 결과를 얻는다.

$ curl -X GET "localhost:9200/my_nori/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
   "analyzer":"my_nori",
   "text":"자연어처리란????!"
}'
{
  "tokens" : [
    {
      "token" : "자연어",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "processing",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "SYNONYM",
      "position" : 1
    },
    {
      "token" : "처리",
      "start_offset" : 3,
      "end_offset" : 5,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "란",
      "start_offset" : 5,
      "end_offset" : 6,
      "type" : "word",
      "position" : 2
    }
  ]
}
$ curl -X GET "localhost:9200/my_nori/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
   "analyzer":"my_nori",
   "text":"기계학습A12"
}'
{
  "tokens" : [
    {
      "token" : "ML",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "SYNONYM",
      "position" : 0
    },
    {
      "token" : "기계학습",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "AAA",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "word",
      "position" : 1
    }
  ]
}

위와 같이 cmd에서 curl을 통한 Elasticsearch의 analyzer 실행은 간단히 테스트하는 용도가 좋습니다. 데이터 분석용은 키바나, 포스트맨 등의 툴을 사용하고, 색인 시에는 주로 ES가 제공해주는 RESTful API를 활용한 프로그래밍으로 진행합니다.

참고.