Elasticsearch 동의어란?
검색 엔진의 최고봉(?)인 elasticsearch에서 동의어 기능은 일상생활 검색 기능에서 필수적인 부분이다. "동의어" 라는 말 그대로 A라는 단어(검색어)를 B와 동일하게 볼 수 있도록 하는 기능이다.
지역별 단어 사용 차이라던지, 복수 단수 형 차이라던지 아니면 일반적인 동의어 영역에서 거의 비슷한 단어들이 존재하는 경우 또는 전문가와 비전문가의 언어차이 등에 동의어 기능을 사용하면 유저의 검색 경험을 훨씬 수월하게 만들 수 있습니다.
examples
ex1) lift => elevator
ex2) houses => house
ex3) tired => exausted
ex4) iPod, ipod => i-Pod
ex5) canine => dog
elasticsearch 동의어 사용법은 아래 두 가지가 있다.
색인 시 동의어 사용 vs 검색 시 동의어 사용 비교
색인 시 동의어 사용
: 색인 시 동의어 필터를 적용하여 색인되는 문서의 단어들이 최종적으로 대체되거나 확장되어 그 결과 검색 인덱스에서 계속 지속된다.
단점
1) 인덱스가 더 커질 수 있다. (모든 동의어가 색인되어야 하기 때문)
2) 용어 통계에 의존하는 검색 점수는 동의어들도 개수 계산하기 때문에 자주 사용되지않는 단어들에 대한 통계가 왜곡될 수 있다.
3) 동의어 규칙은 재색인(reindexing) 없이 기존 문서에 대해 변경될 수 없다.
장점
1) 성능이 좋다.
- 확장 프로세스에 대한 대가를 인덱싱 시 모두 치르기 때문에 쿼리를 날릴 때마다 수행할 필요가 없기 때문이다.
검색 시 동의어 사용
: 검색 시 동의어를 사용하게 된다면 위에서 언급된 색인 시 동의어 사용의 단점 중 많은 부분이 발생하지 않는다.
장점
1) 인덱스 크기에 영향을 미치지 않는다.
2)모음의 용어 통계가 동일하게 유지된다.
3) 동의어 규칙이 변경되어도 문서를 재색인하지 않아도 된다.
단점
1) 쿼리를 날릴 때마다 매번 동의어 확장을 수행해야 하고 잠재적으로 일치시켜야 하는 단어가 더 많다.
=> 결론 : 검색 시 동의어 사용하는 것이 색인 시 동의어 사용하는 이득(성능이 약간 좋은)보다 더 좋다.
실 습 🐠
: 색인 시 동의어 사용해보기
동의어 txt 파일 작성
elasticsearch config있는 곳에 synonym.txt 파일 만들고 내용 작성
나는 Brew로 es 설치해서 path는 아래와 같다
/opt/homebrew/etc/elasticsearch/config/synonym.txt
config 파일이 없으면 mkdir로 만들고 txt file은 vi 로 만들어 준다.
* 만약 위치를 못찾겠다면 아래 명령어로 위치 path를 볼 수 있다.
brew info elasticsearch
synonym.txt 내용
서울, 서울시 => 서울특별시
부산, 부산시 => 부산광역시
서울, 서울시는 모두 서울특별시와 동일하게 검색되도록, 부산, 부산시도 부산광역시와 동일하게 검색되도록 하겠다 ~ 의미
synonym_test 라는 인덱스 생성
PUT synonym_test
{
"settings": {
"index": {
"analysis": {
"analyzer": {
"synonym_analyzer": {
"tokenizer": "whitespace",
"filter": ["my_synonyms"]
}
},
"filter": {
"my_synonyms": {
"type": "synonym",
"synonyms_path": "synonym.txt",
"updateable": true
}
}
}
}
},
"mappings": {
"properties": {
"city": {
"type": "text",
"search_analyzer": "synonym_analyzer"
}
}
}
}
* mappings & settings 까지!
+ settings의 filter에 해당 txt 파일의 위치를 적고,
updateable: true를 꼭 해준다. => txt 나중에 변경될 수 있도록 =====> 요 부분을 조금 더 첨언하자면 Local에서 진행할 때는 updateable:true 를 해주어도 문제가 없었는데 실제 elasticsearch.com 서버에 동의어 Txt 파일들을 넣은 dictionaries.zip 을 올리고 해당 txt파일을 적용한 index를 생성하려니 오류가 났다.
차이는 local에 Txt 파일을 올린 것과 ES서버에 zip/.tt 파일을 올린 것인데 아무래도 local txt 파일 Path 그대로 사용하고update 수정하면 바로 Reload해서 사용하면 되지만 es 서버에 올린 Txt 파일은 reload가 아닌 재배포가 필요해서 해당 "updateable" 기능을 아예 제거해야 하는 것 같다.
updateable 업데이트가 가능하게 만들어버리면 나중에 검색 시에 혼란을 가져올 수 있다는 es 직원의 댓글을 보고 지우고 index생성해보니 잘 되었다.
관련 포스팅 👇
데이터 입력하기
POST synonym_test/_doc
{
"city": "서울특별시"
}
POST synonym_test/_doc
{
"city": "부산광역시"
}
검색해보기
GET synonym_test/_search
{
"query":{
"match":{
"city": "부산"
}
}
}
=> 부산광역시 document가 나온다.
부산, 부산시로 검색하면 부산광역시가 (그 외의 "서", "광역", "광역시" 등으로는 검색되지 않는다.) 서울, 서울시는 서울특별시 document가 나온다.
분석해보기
GET synonym_test/_analyze
{
"analyzer": "synonym_analyzer",
"text": "부산"
}
결과
{
"tokens" : [
{
"token" : "부산광역시",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
}
]
}
여기까지 잘 되었다. 이제 txt 파일 안 내용 (동의어 사전)이 변경될 경우
synonym.txt 파일에 한 줄 추가하기
서울, 서울시 => 서울특별시
부산, 부산시 => 부산광역시
울산, 울산시, 울산광역시
=> 기호는 한 방향 동의어 사전이고 "," 콤마만 있는 경우는 그 line의 모든 단어가 동일하게 쓰인다는 의미
데이터 추가
POST synonym_test/_doc
{
"city": "울산광역시"
}
조회해보기
그대로 "울산" search 해보면 아무 document가 잡히지 않는다.
GET synonym_test/_search
{
"query":{
"match":{
"city": "울산"
}
}
}
이 경우 이전에는 index를 close해놓고 무언가(?)를 했다고 하는데 이제 ES v7.3 부터는 reload 기능을 쓰면 reindexing하지 않고 편하게 동의어 사전 변경 내용을 Update할 수 있다.
해당 Index reload 하기
POST synonym_test/_reload_search_analyzers
다시 조회하기
GET synonym_test/_analyze
{
"analyzer": "synonym_analyzer",
"text": "울산"
}
결과
{
"tokens" : [
{
"token" : "울산",
"start_offset" : 0,
"end_offset" : 2,
"type" : "word",
"position" : 0
},
{
"token" : "울산시",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
},
{
"token" : "울산광역시",
"start_offset" : 0,
"end_offset" : 2,
"type" : "SYNONYM",
"position" : 0
}
]
}
울산, 울산시, 울산광역시 모두 동의어이므로 "부산", "서울"과 다르게 3가지 모두 나왔다.
References:
https://www.elastic.co/kr/blog/boosting-the-power-of-elasticsearch-with-synonyms
https://www.skyer9.pe.kr/wordpress/?p=3813
'Elasticsearch' 카테고리의 다른 글
[Elasticsearch] Data Math 개념과 계산하는 방법 (0) | 2022.10.24 |
---|---|
[Elasticsearch] analyzer [ ] contains filters [ ] that are not allowed to run in index time mode (0) | 2022.09.05 |
[elasticsearch] search after란? 사용 방법 알아보기 with node.js (0) | 2022.08.24 |
[Elasticsearch + Node.js] 좌표 거리 구하기 with script_fields arcDistance (0) | 2022.08.23 |
[elasticsearch] dis_max란 무엇인지 알아보기, 실습하기 (bool, must와 함께 쓰기) (0) | 2022.08.19 |