본문 바로가기
웹/elasticsearch

openkoreantext_analyzer start_offset bug

by java개발자 2019. 10. 9.

openkoreantext_analyzer 를 사용하면서, start_offset 값이 원본과 다르게 나오는 현상이 발생하였다.

처음에는 bug인줄 알았는데 해결방법이 있어서 공유한다.

리셋
DELETE openkoreantext_analyzer
{
}

세팅
PUT openkoreantext_analyzer
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "openkoreantext-analyzer": {
            "char_filter": [
              "openkoreantext-normalizer"
            ],            
            "tokenizer": "openkoreantext-tokenizer",
            "filter": [
              "openkoreantext-stemmer",
              "openkoreantext-redundant-filter",
              "lowercase"
            ]
          }
        }
      }
    }
  }
}

실행
POST openkoreantext_analyzer/_analyze 
{
        "analyzer": "openkoreantext-analyzer",
        "text": "걸로 함"
}

결과

{
  "tokens" : [
    {
      "token" : "것",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "Noun",
      "position" : 0
    },
    {
      "token" : "함",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "Noun",
      "position" : 1
    }
  ]
}

설명

결과를 보면, 것(0, 1), 함(4, 5) 이다. <---- token(start_offset, end_offset)

원본 text에서 함은 (3, 4) 위치인데, token으로 오면서 위치가 변경되어 버렸다. 이렇게 되면 추후 token을 이용해서 원본 문장의 키워드 위치 추적이 불가하다.

 

analyzer에 대해 자세히 알아보니, analyze는 여러가지 filter에 의해 작동됨을 확인하였다.

출처: https://github.com/open-korean-text/elasticsearch-analysis-openkoreantext

분석 순서:

[openkoreantext-normalizer] -> [openkoreantext-tokenizer] -> [openkoreantext-stemmer, openkoreantext-redundant-filter, classic, length, lowercase]

 

한번 하나하나 삭제해가면서 테스트해보자.

 

1. analyzer 등록시 tokenizer는 필수라서 tokenizer만 사용한 경우이다.

DELETE openkoreantext_analyzer
{
}
PUT openkoreantext_analyzer
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "openkoreantext-analyzer": {
                   
            "tokenizer": "openkoreantext-tokenizer",
            "filter": [
         
            ]
          }
        }
      }
    }
  }
}
POST openkoreantext_analyzer/_analyze 
{
        "analyzer": "openkoreantext-analyzer",
        "text": "걸로 함"
}

결과
{
  "tokens" : [
    {
      "token" : "걸",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "Noun",
      "position" : 0
    },
    {
      "token" : "로",
      "start_offset" : 1,
      "end_offset" : 2,
      "type" : "Josa",
      "position" : 1
    },
    {
      "token" : " ",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "Space",
      "position" : 2
    },
    {
      "token" : "함",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "Noun",
      "position" : 3
    }
  ]
}

2. openkoreantext-normalizer + tokenizer

openkoreantext-normalizer를 붙이면서 token의 start_offset이 한칸씩 밀렸다.

DELETE openkoreantext_analyzer
{
}
PUT openkoreantext_analyzer
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "openkoreantext-analyzer": {
            "char_filter": [
              "openkoreantext-normalizer"
            ],            
            "tokenizer": "openkoreantext-tokenizer"
          
          }
        }
      }
    }
  }
}
POST openkoreantext_analyzer/_analyze 
{
        "analyzer": "openkoreantext-analyzer",
        "text": "걸로 함"
}
결과
{
  "tokens" : [
    {
      "token" : "것",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "Noun",
      "position" : 0
    },
    {
      "token" : "으로",
      "start_offset" : 1,
      "end_offset" : 3,
      "type" : "Josa",
      "position" : 1
    },
    {
      "token" : " ",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "Space",
      "position" : 2
    },
    {
      "token" : "함",
      "start_offset" : 4,
      "end_offset" : 5,
      "type" : "Noun",
      "position" : 3
    }
  ]
}

 

출처를 참고하면,

Charater Filter
1 openkoreantext-normalizer
구어체를 표준화 합니다.
훌쩍훌쩍훌쩍훌쩍 -> 훌쩍훌쩍, 하겟다 -> 하겠다, 안됔ㅋㅋㅋ -> 안돼ㅋㅋ

2 Tokenizer
openkoreantext-tokenizer
문장을 토큰화 합니다.
한국어를 처리하는 예시입니다 ㅋㅋ -> [한국어, 를, 처리, 하는, 예시, 입니다, ㅋㅋ]

Token Filter
1 openkoreantext-stemmer  * 형용사와 동사를 스테밍합니다.
새로운 스테밍을 추가했었다. -> [새롭다, 스테밍, 을, 추가하다, .]

2 openkoreantext-redundant-filter
접속사, 공백(띄워쓰기), 조사, 마침표 등을 제거합니다.
그리고 이것은 예시, 또는 예로써, 한국어를 처리하기 -> [예시, 예, 한국어, 처리, 하다]

3 openkoreantext-phrase-extractor
어구를 추출합니다.
한국어를 처리하는 예시입니다 ㅋㅋ -> [한국어, 처리, 예시, 처리하는 예시]

 

결론

openkoreantext-normalizer:

구어체를 표준화하는 작업에서 원본 text가 변경되었고, 결국 token의 위치도 변경되었다.

 

 

3. elasticsearch를 이용해서, 구어체가 아닌 문장을 분석하기 때문에 굳이 표준화 작업이 필요없음.

openkoreantext-normalizer 를 삭제함.

DELETE openkoreantext_analyzer
{
}
PUT openkoreantext_analyzer
{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "openkoreantext-analyzer": {
            "tokenizer": "openkoreantext-tokenizer",
            "filter": [
              "openkoreantext-stemmer",
              "openkoreantext-redundant-filter",
              "lowercase"
            ]
          }
        }
      }
    }
  }
}
POST openkoreantext_analyzer/_analyze 
{
        "analyzer": "openkoreantext-analyzer",
        "text": "걸로 함"
}
결과
{
  "tokens" : [
    {
      "token" : "걸",
      "start_offset" : 0,
      "end_offset" : 1,
      "type" : "Noun",
      "position" : 0
    },
    {
      "token" : "함",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "Noun",
      "position" : 1
    }
  ]
}

 

' > elasticsearch' 카테고리의 다른 글

한글 형태소 분석기 비교  (0) 2019.07.05
elasticsearch 에 없는 기능 - return terms  (1) 2019.04.26
test query  (0) 2019.04.26