엘라스틱 서치 분해하기 1
Hermaeus Mora ·
정규화로 검색하니 해당 단어가 포함되지 않은 글이 검색되었다. 그 글에는 동기화란 단어가 포함되어 있었는데, 왜 검색이 된 것일까?
그 이유를 살펴보자.
우선 다음과 같은 인덱스를 만든다.
PUT test1
{
\"settings\": {
\"index\": {
\"analysis\": {
\"tokenizer\": {
\"nori_user_dict\": {
\"type\": \"nori_tokenizer\",
\"decompound_mode\": \"mixed\"
}
},
\"analyzer\": {
\"my_analyzer\": {
\"type\": \"custom\",
\"tokenizer\": \"nori_user_dict\"
}
}
}
}
}
}해당 인덱스는 토크나이저로 nori라는 형태소 분석기를 사용한다. decompound_mode라는 옵션이 있는데, 이는 합성어를 어떻게 분해할지를 결정한다. 다음 3가지 옵션을 선택할 수 있다. none : 어근을 분리하지 않고 완성된 합성어만 저장 discard (디폴트) : 합성어를 분리하여 각 어근만 저장 mixed : 어근과 합성어를 모두 저장
어근을 분리하지 않는다면 형태소 분석기를 쓸 이유가 없으므로 mixed를 사용한다.
그리고 해당 인덱스의 애널라이저를 통해 정규화라는 합성어를 분해해보자.
GET test1/_analyze
{
\"analyzer\": \"my_analyzer\",
\"text\": \"정규화\",
\"explain\": true
}{
\"detail\": {
\"custom_analyzer\": true,
\"charfilters\": [],
\"tokenizer\": {
\"name\": \"nori_user_dict\",
\"tokens\": [
{
\"token\": \"정규\",
...,
\"leftPOS\": \"NNG(General Noun)\",
},
{
\"token\": \"화\",
...,
\"leftPOS\": \"XSN(Noun Suffix)\",
}
]
},
\"tokenfilters\": []
}
}그럼 다음과 같이 정규 + 화로 분해되는 것을 볼 수 있다.
‘-화(化)’는 (일부 명사 뒤에 붙어) '그렇게 만들거나 됨'의 뜻을 더하는 접미사(Noun Suffix, XSN)이다.
동기화도 같은 방식으로 어근이 분리되어 동기 + 화로 저장되기 때문에, 정규화로 검색 시 ~화 접미사가 분리되어서 해당 접미사를 포함한 모든 도큐먼트를 검색해오는것이다.
이러한 검색 품질 저하를 막기 위해 특정 유형의 어근을 색인하지 않도록 막을 수 있다. 다음과 같이 test2 인덱스를 생성하자.
PUT test2
{
\"settings\": {
\"index\": {
\"analysis\": {
\"tokenizer\": {
\"nori_user_dict\": {
\"type\": \"nori_tokenizer\",
\"decompound_mode\": \"mixed\"
}
},
\"analyzer\": {
\"my_analyzer\": {
\"type\": \"custom\",
\"tokenizer\": \"nori_user_dict\",
\"filter\": [ \"nori_filter\" ]
}
},
\"filter\": {
\"nori_filter\": {
\"type\": \"nori_part_of_speech\",
\"stoptags\": [\"XSN\"]
}
}
}
}
}
}nori_part_of_speech 필터는 stoptags 옵션을 제공하는데, 해당 옵션에 명시된 유형의 어근들은 색인되지 않는다. 실제로 분석해보면
GET test2/_analyze
{
\"analyzer\": \"my_analyzer\",
\"text\": \"동기화\",
\"explain\": true
}{
\"detail\": {
\"custom_analyzer\": true,
\"charfilters\": [],
\"tokenfilters\": [
{
\"name\": \"nori_filter\",
\"tokens\": [
{
\"token\": \"동기\",
...,
\"leftPOS\": \"NNG(General Noun)\",
}
]
}
]
}
}접미사를 색인하지 않고 있는것을 확인할 수 있다. stoptags에 아무 값도 명시하지 않는 경우의 디폴트 값은 다음과 같다.
\"stoptags\": [
\"E\", \"IC\", \"J\", \"MAG\", \"MAJ\", \"MM\", \"SP\", \"SSC\", \"SSO\", \"SC\", \"SE\", \"XPN\", \"XSA\", \"XSN\", \"XSV\", \"UNA\", \"NA\", \"VSV\"
]UNA, NA, VSV는 의미없는 값이라고 생각해도 무방하다. 이 사이트의 경우 다음의 stoptags를 사용한다.
\"stoptags\": [
\"E\", \"J\", \"MM\", \"NNB\", \"SP\", \"SSC\", \"SSO\", \"SC\", \"SE\", \"SF\", \"XSA\", \"XSN\", \"XSV\"
]IC (감탄사), MAG, MAJ (부사), XPN(접두사)를 색인하는 점이 다르다. 그 외의 색인하지 않는 값들의 의미는 다음과 같다.
E: 어미 -거든, -게, -겠-, -고, -나, -는(-), -다, -(ㄴ)다손, -대, -데, -러, -려, -며, -면, -어서, -시-, -야, -었-, -요, -읍니다, -지, -ㄹ, -ㅁ 등
J: 조사 이/가, (으)로써, 에서, 에게서, 부터, 까지, 에게, 한테, 께, 와/과, 에서, 을/를, 의, 로서, 로, 을/를 등
MM: 관형사 새, 헌, 첫, 옛, 윗, 뒷, 온, 뭇, 한, 온갖, 갖은, 외딴, 오른, 왼, 참, 거짓, 이, 그, 저, 요, 고, 조, 이런, 저런, 그런, 무슨, 어느, 딴, 아무, 한, 두, 세(석), 네(넉), 다섯, 여섯, 일, 이, 삼, 반, 전(全), 총(總) 등
NNB: 의존 명사 지, 수, 리, 나위 이, 것, 데, 바, 따위, 줄, 뿐 때문, 나름, 따름, 뿐, 터 만큼, 대로, 듯, 양, 체, 채, 척, 등, 뻔, 만 등
단위성 의존명사 (NNBC)는 인덱싱한다. 개, 마리, 장, 권, 켤레, 줄, 몰, 미터(길이), 킬로그램(무게), 리터(부피), 달러(화폐 단위), 칼로리(열량), 쿼터(스포츠 시간), 바이트(데이터량), 파스칼(기압), 헤르츠(진동), 데시벨(소리) 등
SP: Space SSC: Closing brackets ({, (, [)
SSO: Opening brackets (}, ), ]) SC: Separator (·, /, :) SE: Ellipsis (...) SF: Terminal punctuation (?,!,.)
XSA: 형용사 파생 접미사 -하-, -되-, -지-, -롭-, -스럽-, -답-, -다랗-, -맞-, -없-, -쩍- 등
XSN: 명사 파생 접미사 -성, -ㅁ(기다림, 조림) 등
XSV: 동사 파생 접미사 -하-, -거리-, -대-, -이-, -뜨리-, -트리-, -되- 등