[Elasticsearch] Synonym filter 테스트

Elastic/Elasticsearch 2018. 4. 19. 16:19

커뮤니티에 질문 주신 내용이 있어서 바쁘지만 테스트 결과 공유 드립니다.

커뮤니티에 질문 올려 주신 분이 계셔서 직접 테스트 진행 했습니다.

제가 position 관련 에러 수정을 위한 테스트 시간이 없어서 인명 사전 등록 방법으로 처리 했는데요.

수정이 필요 하시면 KoreanFilter 코드를 수정 하시면 됩니다.


설치 및 테스트 Elasticsearch Version)

6.0.0


Arirang plugin 설치)

$ bin/elasticsearch-plugin install https://github.com/HowookJeong/elasticsearch-analysis-arirang/releases/download/6.0.0/elasticsearch-analysis-arirang-6.0.0.zip


Index 삭제)

DELETE syntest


{

  "error": {

    "root_cause": [

      {

        "type": "index_not_found_exception",

        "reason": "no such index",

        "resource.type": "index_or_alias",

        "resource.id": "syntest",

        "index_uuid": "_na_",

        "index": "syntest"

      }

    ],

    "type": "index_not_found_exception",

    "reason": "no such index",

    "resource.type": "index_or_alias",

    "resource.id": "syntest",

    "index_uuid": "_na_",

    "index": "syntest"

  },

  "status": 404

}


Index 생성)

PUT /syntest

{

  "settings": {

    "index.number_of_shards": 1,

    "index.number_of_replicas": 0,

    "index": {

      "analysis": {

        "analyzer": {

          "arirang_custom": {

            "tokenizer": "arirang_tokenizer",

            "filter": [

              "lowercase",

              "trim",

              "custom_synonym",

              "arirang_filter"

            ]

          }

        },

        "filter": {

          "custom_synonym": {

            "type": "synonym",

            "synonyms": [

              "henry,헨리,앙리",

              "신해철,마왕"

            ]

          }

        }

      }

    }

  }

}


{

  "acknowledged": true,

  "shards_acknowledged": true,

  "index": "syntest"

}


Analyze 실행)

GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "custom_synonym",

    "arirang_filter"

  ],

  "text": "신해철"

}


{

  "tokens": [

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "신해",

      "start_offset": 0,

      "end_offset": 2,

      "type": "korean",

      "position": 0

    },

    {

      "token": "해철",

      "start_offset": 1,

      "end_offset": 3,

      "type": "korean",

      "position": 1

    },

    {

      "token": "마왕",

      "start_offset": 0,

      "end_offset": 3,

      "type": "SYNONYM",

      "position": 1

    }

  ]

}


동의어 처리가 되지 않은 이유)

GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "text": "신해철은 henry"

}


{

  "tokens": [

    {

      "token": "신해철은",

      "start_offset": 0,

      "end_offset": 4,

      "type": "korean",

      "position": 0

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 1

    }

  ]

}


tokenizer 에서 추출한 토큰은 위와 같이 두개 입니다.

아래는 filter 를 적용한 내용입니다.


GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "custom_synonym",

    "arirang_filter"

  ],

  "text": "신해철은 henry"

}


{

  "tokens": [

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "신해철은",

      "start_offset": 0,

      "end_offset": 4,

      "type": "korean",

      "position": 0

    },

    {

      "token": "신해",

      "start_offset": 0,

      "end_offset": 2,

      "type": "korean",

      "position": 0

    },

    {

      "token": "해철",

      "start_offset": 1,

      "end_offset": 3,

      "type": "korean",

      "position": 1

    },

    {

      "token": "철은",

      "start_offset": 2,

      "end_offset": 4,

      "type": "korean",

      "position": 2

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 3

    },

    {

      "token": "헨리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 3

    },

    {

      "token": "앙리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 3

    }

  ]

}


위에 추출된 term 목록을 보면 "마왕" 이라는 동의어가 추가 되지 않은것을 볼 수 있습니다.

이것은 두 가지 방법으로 해결이 가능 합니다.

사전에 "신해철" 이라는 인명 사전 정보를 등록 하시면 됩니다.

기본적으로 tokenzier 과정 후 filter 처리가 되면서 사전에 등록된 정보로 term 구성이 되기 때문에 사전에 누락 된 경우는 일반적으로 KoreanFilter 에 의해서 bigram 처리가 됩니다.

다른 한 가지는 position 정보가 구성 시 오류가 나지 않도록 코드를 수정 하는 것입니다.

KoreanFilter 코드를 참고 하셔서 테스트 및 수정 하시면 됩니다.


아래는 사전에 "신해철" 추가 후 실행한 방법 입니다.


GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "arirang_filter",

    "custom_synonym"

  ],

  "text": "신해철은 henry"

}


{

  "tokens": [

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "마왕",

      "start_offset": 0,

      "end_offset": 3,

      "type": "SYNONYM",

      "position": 0

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 1

    },

    {

      "token": "헨리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 1

    },

    {

      "token": "앙리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 1

    }

  ]

}


: