반응형
Recent Posts
Recent Comments
관리 메뉴

개발잡부

[es] function score Query 본문

ElasticStack/Elasticsearch

[es] function score Query

닉의네임 2021. 12. 20. 11:18
반응형

데이터 입력 후 확인

POST _bulk
{"index":{"_index":"doo", "_id":"1"}}
{"name":"나이키", "weight" : 1, "boost" : 1, "description" : "나이키 상품"}
{"index":{"_index":"doo", "_id":"2"}}
{"name":"나이키 에이맥스","weight" : 1, "boost" : 1,"description" : "나이키 운동화"}
{"index":{"_index":"doo", "_id":"3"}}
{"name":"나이키 에어조던","weight" : 1, "boost" : 1,"description" : "나이키 운동화 농구화"}
{"index":{"_index":"doo", "_id":"4"}}
{"name":"나이키 에어조단","weight" : 1, "boost" : 1,"description" : "나이키 운동화 농구화"}
{"index":{"_index":"doo", "_id":"5"}}
{"name":"나이키 후드티","weight" : 1, "boost" : 1,"description" : "나이키 의류"}
{"index":{"_index":"doo", "_id":"6"}}
{"name":"나이키 후드집업", "weight" : 1, "boost" : 1,"description" : "나이키 의류 자켓"}
{"index":{"_index":"doo", "_id":"7"}}
{"name":"나이키 후드나시티","weight" : 1, "boost" : 1,"description" : "나이키 의류 속옷"}
{"index":{"_index":"doo", "_id":"8"}}
{"name":"나이키 후드점퍼","weight" : 1, "boost" : 1,"description" : "나이키 의류 자켓"}
{"index":{"_index":"doo", "_id":"9"}}
{"name":"나이키 후드트레이닝","weight" : 1, "boost" : 1,"description" : "나이키 의류"}
{"index":{"_index":"doo", "_id":"10"}}
{"name":"나이키 트레이닝","weight" : 1, "boost" : 1,"description" : "나이키 의류 트레이닝"}

 

GET doo/_search?pretty
{
  "query": {
    "function_score": {
      "query": { "match_all": {} },
      "boost": "5", 
      "functions": [
        {
          "filter": { "match": { "name": "나이키" } },
          "random_score": {}, 
          "weight": 12
        },
        {
          "field_value_factor": {
            "field": "boost"
          }, 
          "filter": { "match": { "description": "상품" } },
          "weight": 5
        }
      ],
      "max_boost": 50,
      "score_mode": "multiply",
      "boost_mode": "multiply",
      "min_score": 1
    }
  }
}

 

 

테스트 코드

import json
import time

from elasticsearch import Elasticsearch

def handle_query():
    script_query = {
        "function_score": {
            "query": {"match_all": {}},
            "boost": "5",
            "functions": [
                {
                    "filter": {"match": {"name": "나이키"}},
                    "random_score": {},
                    "weight": 12
                },
                {
                    "field_value_factor": {
                        "field": "boost"
                    },
                    "filter": {"match": {"description": "상품"}},
                    "weight": 5
                }
            ],
            "max_boost": 50,
            "score_mode": "multiply",
            "boost_mode": "multiply",
            "min_score": 1
        }
    }

    search_start = time.time()
    response = client.search(
        index=INDEX_NAME,
        body={
            "size": SEARCH_SIZE,
            "query": script_query,
            "_source": {"includes": ["name", "description", "weight", "boost"]}
        }
    )
    search_time = time.time() - search_start

    print()
    print("{} total hits.".format(response["hits"]["total"]["value"]))
    print("search time: {:.2f} ms".format(search_time * 1000))

    for hit in response["hits"]["hits"]:
        print("id: {}, score: {}".format(hit["_id"], hit["_score"]))
        print(hit["_source"]["name"] + " - " + hit["_source"]["description"])



if __name__ == '__main__':
    INDEX_NAME = "doo"

    SEARCH_SIZE = 10
    GPU_LIMIT = 0.5
    client = Elasticsearch(http_auth=('elastic', 'datalake'))
    handle_query()
    print("Done.")

 

score_mode : If no filter is given with a function this is equivalent to specifying "match_all": {}

multiply 점수가 곱해집니다(기본값)
sum 점수 합산
avg 점수는 평균
first 일치하는 필터가 있는 첫 번째 함수가 적용됩니다.
max 최대 점수가 사용됩니다
min 최소 점수가 사용됩니다.

 

boost_mode : The newly computed score is combined with the score of the query.

multiply 쿼리 점수와 함수 점수가 곱해집니다(기본값).
replace 함수 점수만 사용되며 쿼리 점수는 무시됩니다.
sum 쿼리 점수 및 기능 점수 추가
avg 평균
max 쿼리 점수 및 기능 점수의 최대값
min 최소 쿼리 점수 및 기능 점수

 

script_score

GET doo/_search?pretty
{
  "query": {
    "function_score": {
      "query": {
        "match": { "name": "나이키 후드" }
      },
      "script_score": {
        "script": {
          "source": "Math.log(2 + doc['pop'].value)"
        }
      }
    }
  }
}

 

시연당할 재물

 

pop 를 업데이트 해보자

POST _bulk
{"update":{"_index":"doo", "_id":"5"}}
{"doc":{"pop":3}}

1등이된 부정행위 후드

 

 

GET doo/_search?pretty
{
  "query": {
    "function_score": {
      "query": {
        "match": { "name": "나이키 후드" }
      },
      "script_score": {
        "script": {
          "params": {
            "a": 5,
            "b": 1.2
          },
          "source": "params.a / Math.pow(params.b, doc['pop'].value)"
        }
      },
      "boost_mode": "replace"
    }
  }
}

 

weight

"weight" : number

 

random_score

GET doo/_search?pretty
{
  "query": {
    "function_score": {
      "random_score": {
        "seed": 10,
        "field": "pop"
      }
    }
  }
}

 

import json
import time
import matplotlib.pyplot as plt
import numpy as np

from elasticsearch import Elasticsearch



if __name__ == '__main__':
    INDEX_NAME = "doo"
    SEARCH_SIZE = 10
    GPU_LIMIT = 0.5
    client = Elasticsearch(http_auth=('elastic', 'datalake'))
    print("Done.")


    script_query = {
        "function_score": {
            "query": {"match_all": {}},
            "boost": "5",
            "functions": [
                {
                    "filter": {"match": {"name": "나이키"}},
                    "random_score": {},
                    "weight": 12
                },
                {
                    "filter": {"match": {"description": "상품"}},
                    "weight": 5
                }
            ],
            "max_boost": 50,
            "score_mode": "multiply",
            "boost_mode": "multiply",
            "min_score": 1
        }
    }

    search_start = time.time()
    response = client.search(
        index=INDEX_NAME,
        body={
            "size": SEARCH_SIZE,
            "query": script_query,
            "_source": {"includes": ["name", "description", "weight", "boost"]}
        }
    )
    search_time = time.time() - search_start

    print()
    print("{} total hits.".format(response["hits"]["total"]["value"]))
    print("search time: {:.2f} ms".format(search_time * 1000))
    x = np.arange(SEARCH_SIZE)
    years = []
    values = []
    for hit in response["hits"]["hits"]:
        print("id: {}, score: {}".format(hit["_id"], hit["_score"]))
        print(hit["_source"]["name"] + " - " + hit["_source"]["description"])
        years.append(hit["_source"]["name"])
        values.append(hit["_score"])
    plt.rcParams['font.family'] = 'AppleGothic'
    plt.bar(x, values)
    plt.xticks(x, years)
    plt.show()

 

한글깨짐 문제

plt.rcParams['font.family'] = 'AppleGothic'

 

 

Windows OS

나눔고딕 폰트가 설치되어 있다면,

plt.rcParams['font.family'] = 'NanumGothic'

맑은고딕 폰트가 설치되어 있다면,

plt.rcParams['font.family'] = 'Malgun Gothic'

Mac OS

Apple Gothic 이 설치되어 있다면,

plt.rcParams['font.family'] = 'AppleGothic'

 

 

반응형

'ElasticStack > Elasticsearch' 카테고리의 다른 글

[es] query score test  (0) 2021.12.26
[es] multi-match query  (0) 2021.12.20
[es] plugin 4 - custom analyzer 사용  (0) 2021.12.15
[es] plugin 3 - custom analyzer  (0) 2021.12.12
[es] Analyzer 01  (0) 2021.12.08
Comments