Table of Contents
ElasticSearch score 커스터마이징
ES 는 기본값으로 BM25
알고리즘을 이용해 score
를 계산합니다.
BM25 알고리즘
검색키워드의 빈도수, 문서상의 키워드의 빈도수, 문서의 크기 등을 기준으로 score 를 산정합니다.
TF(Term Frequency)
문서 내에서 자주 등장하는 단어(Term) 에 가중치를 높게 부여합니다.
IDF(Inverse Document Frequency)
많은 문서에서 등장하는 단어(Term) 의 가중치는 낮추고, 일부 문서에서만 등장하는 단어(Term) 에 대해 높은 가중치를 부여합니다.
문서의 종류를 가리지 않고 자주 등장하는 단어는 별 의미없는 흔한 단어일 가능성이 높기 때문입니다.
Field-length norm
두개 이상의 문서에서 동일한 키워드가 동일한 빈도수로 등장한다고 가정할 때, 문서의 길이가 작은 문서에 더 높은 가중치를 부여합니다.
score 커스터마이징
하지만 쇼핑몰에서는 검색어의 빈도수만 가지고 score 를 산정할 수 없습니다.
간단하게 아이폰
이라는 키워드와 기존 고객들이 검색 후 클릭한 수, 구매한 수가 높은 상품에 우선순위를 더 부여할 필요가 있습니다.
아래에서 function_score
를 이용해 위 기능을 구현해 봅니다.
참조 사이트
기본설정
여기 에 설명된 서버설정을 기초로 수정합니다.
테이블 준비
CREATE DATABASE db_test DEFAULT CHARACTER SET UTF8 COLLATE UTF8_GENERAL_CI;
USE db_test;
DROP TABLE IF EXISTS items;
CREATE TABLE items (
itemid BIGINT(20) UNSIGNED NOT NULL,
PRIMARY KEY (itemid),
UNIQUE KEY unique_id (itemid),
itemname VARCHAR(128) NOT NULL,
viewKeywords VARCHAR(2048) NOT NULL,
buyKeywords VARCHAR(2048) NOT NULL,
lastupdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
regdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO items (itemid, itemname, viewKeywords, buyKeywords)
VALUES (1, '블랙 아이폰 케이스', '아이폰 케이스', '');
INSERT INTO items (itemid, itemname, viewKeywords, buyKeywords)
VALUES (2, '블랙 갤럭시 케이스', '갤럭시', '갤럭시');
INSERT INTO items (itemid, itemname, viewKeywords, buyKeywords)
VALUES (3, '핑크 아이폰 케이스', '아이폰', '');
INSERT INTO items (itemid, itemname, viewKeywords, buyKeywords)
VALUES (4, '화이트 갤럭시 케이스', '', '');
INSERT INTO items (itemid, itemname, viewKeywords, buyKeywords)
VALUES (5, '래드 아이폰 케이스', '케이스', '아이폰');
조회키워드와 구매키워드를 데이타로 입력해 줍니다.
인덱스 준비
curl -XDELETE http://localhost:9200/items?pretty
curl -XPUT http://localhost:9200/items?pretty -H 'Content-Type: application/json' -d '{
"settings" : {
"index":{
"analysis":{
"analyzer":{
"korean":{
"type":"custom",
"tokenizer":"seunjeon_default_tokenizer",
"filter" : ["synonym", "stopword", "lowercase"]
}
},
"filter" : {
"synonym" : {
"type" : "synonym",
"synonyms_path" : "synonyms.txt"
},
"stopword" : {
"type" : "stop",
"stopwords_path" : "stopwords.txt"
}
},
"tokenizer": {
"seunjeon_default_tokenizer": {
"index_eojeol": "true",
"user_dict_path": "user_dict.csv",
"index_poses": [
"UNK", "EP", "I", "J", "M",
"N", "SL", "SH", "SN", "VCP",
"XP", "XS", "XR"
],
"decompound": "true",
"type": "seunjeon_tokenizer"
}
}
}
}
},
"mappings" : {
"_doc" : {
"properties" : {
"itemid" : {
"type" : "integer"
},
"itemname" : {
"type" : "text",
"analyzer": "korean"
},
"viewKeywords" : {
"type" : "text",
"analyzer": "korean"
},
"buyKeywords" : {
"type" : "text",
"analyzer": "korean"
},
"lastupdate" : {
"type" : "date"
},
"regdate" : {
"type" : "date"
}
}
}
}
}'
가중치를 부여한 검색
curl -X GET "localhost:9200/items/_search?pretty" -H 'Content-Type: application/json' -d'{
"query": {
"function_score": {
"query": { "match": { "itemname": "아이폰 케이스" } },
"boost": "5",
"functions": [
{
"filter": { "match": { "viewKeywords": "아이폰 케이스" } },
"random_score": {},
"weight": 23
},
{
"filter": { "match": { "buyKeywords": "아이폰 케이스" } },
"weight": 42
}
],
"max_boost": 42,
"score_mode": "max",
"boost_mode": "multiply",
"min_score" : 0
}
}
}'
https://ldh-6019.tistory.com/181
https://ksk-developer.tistory.com/27