elasticsearch는 version 7이후를 기준으로 BM25로 score계산을 한다.
키워드가 문서에 얼마나 자주 나타나는지, 모든 문서에서 자주 등장하는지 특정 문서에서만 자주 등장하는지를 계산하여 키워드의 중요도에 따른 검색 결과를 뽑아내는데 최적화 되어있다.
BM25는 TF-IDF를 기반으로 설계되었다.
그 외의 알고리즘으로
"similarity": "classic"
로 사용할 수 없음. 밑에 나올 script
로 적용 가능하다. "NAME" : {
"type" : "text",
"term_vector" : "with_positions_offsets",
"analyzer" : "analyzer",
"search_analyzer" : "search_analyzer",
"similarity": "boolean"
}
Name
필드에선 score계산이 되지 않도록 위에 언급한 boolean을 적용하였다.
text타입만 similarity
적용이 가능하다. 적용하지 않은 필드는 디폴트 BM25로 계산된다.
[참고] https://www.elastic.co/guide/en/elasticsearch/reference/current/similarity.html
"similarity":"boolean"
를 준 필드는 score가 모두 1이다.
검색 쿼리 작성시 해당 필드에 boost로 score를 계산하려 한다.
{
"match_phrase": {
"NAME": {
"query": "simple rest apis distributed nature",
"boost": 2
}
}
}
꼭 boolean이 아니고 BM25에도 boost 부여 가능하다.
다만, boost를 주면 검색 속도의 문제는 있을 수 있어보인다.
POST _scripts/demo_search_template
{
"script": {
"lang": "mustache",
"source": {
"query": {
"bool": {
"should": [
{
"match": {
"content": {
"query": "{{query_string}}"
}
}
},
{
"match": {
"content": {
"query": "{{query_string}}",
"operator": "and"
}
}
},
{
"match_phrase": {
"content": {
"query": "{{query_string}}",
"boost": 2
}
}
}
]
}
}
}
}
}
<template 사용>
GET _search/template
{
"id": "demo_search_template",
"params": {
"query_string": "simple rest apis distributed nature"
}
}
similarity module은 setting
에 원하는 score계산 similarity
를 정의하고 mapping
의 필드에 맞는 similarity
를 적용한다.
ex) DFR score계산
[setting]
PUT /index
{
"settings": {
"index": {
"similarity": {
"my_similarity": {
"type": "DFR",
"basic_model": "g",
"after_effect": "l",
"normalization": "h2",
"normalization.h2.c": "3.0"
}
}
}
}
}
[mapping에 원하는 필드에 사용]
PUT /index/_mapping
{
"properties" : {
"title" : {
"type" : "text",
"similarity" : "my_similarity"
}
}
}
BasicModel, AffterEffect, Normalization 이 3가지 요소로 DFR이 구성된다.
각 파라미터값은 아래를 참고하여 설정가능하다.
[참고] https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-similarity.html#_available_similarities
[elasticsearch relevancy/score/ 검색 작동] https://qbox.io/blog/practical-guide-elasticsearch-scoring-relevancy
"similarity": {
"scripted_tfidf": { //7이전의 tfidf 로 score계산하려면 script를 이용해 만든다.
"type": "scripted",
"script": {
"source": "double tf = Math.sqrt(doc.freq); double idf = Math.log((field.docCount+1.0)/(term.docFreq+1.0)) + 1.0; double norm = 1/Math.sqrt(doc.length); return query.boost * tf * idf * norm;"
}
},
"scripted_tf": { //tf만(필드에서만 빈도) score계산하고 싶으면.
"type": "scripted",
"script": {
"source": "double tf = Math.sqrt(doc.freq); return query.boost * tf"
}
}
},
이렇게 계산할 방법을 painless script로 정의한뒤 mapping의 해당 필드에 정의한 similarity를 설정하면 된다.
[참고] painless similarity
https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-similarity-context.html
"NAME": {
"type": "text",
"term_vector": "with_positions_offsets",
"analyzer": "analyzer",
"search_analyzer": "search_analyzer",
"similarity": "script_tf"
}
scripted_tfidf
는 tf-idf 알고리즘이고 scripted_tf
은 이를 변경한 tf로만 score계산하는 방법이다.
[참고]
similarity로 score를 수정하고, function_score 구현하기
https://ksk-developer.tistory.com/27
function_score : score를 조작할 수 있도록 해준다. 기본적으로 tf-idf와 bm25를 사용한다. 이 디폴트 알고리즘으로 원하는 결과를
받지 않는다면, function_score로 값을 조정해보자!
다양한 방법의 score 조정(function_score, boosting, 스코어 결합)
https://kazaana2009.tistory.com/6
위의 여러가지 score 계산을 통한 정렬 구현 (무신사)
https://velog.io/@choi-yh/%EA%B2%80%EC%83%89%EC%97%94%EC%A7%84-%EB%AC%B4%EC%8B%A0%EC%82%AC-%EA%B2%80%EC%83%89-%EC%B6%94%EC%B2%9C-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EC%A0%95%EB%A6%AC
https://kazaana2009.tistory.com/6
https://heesutory.tistory.com/30
https://m.blog.naver.com/olpaemi/222003279473
[bm25, tf-idf]
https://velog.io/@mayhan/Elasticsearch-%EC%9C%A0%EC%82%AC%EB%8F%84-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98