序文
elasticsearch
これは非常に強力な検索機能を提供しますが、相関スコアを使用するだけでは不十分な場合があるため、elasticsearch
カスタム スコアリング関数が提供されますfunction_score
。この記事では、簡単なケースを組み合わせてfunction_score
その使用方法を説明します。function-score-query
最も権威のあるドキュメント公式ドキュメント:
function_score 公式ドキュメント
基本的なデータの準備
次のフィールドを含むニュース テーブルを作成します。
分野 | タイプ | 説明する |
---|---|---|
ID | 長さ | ニュースID |
タイトル | 弦 | タイトル |
タグ | 弦 | ラベル |
read_count | 長さ | 読み取り回数 |
like_count | 長さ | いいね! |
コメント数 | 長さ | コメント |
ランク | ダブル | カスタムウェイト |
位置 | 配列 | 記事掲載時の緯度と経度 |
パブタイム | 日にち | リリースタイム |
作成elasticsearch
者Mapping
:
PUT /news
{
"mappings": {
"properties": {
"id": {
"type": "long"
},
"title": {
"type": "text",
"analyzer": "standard"
},
"tags": {
"type": "keyword"
},
"read_count": {
"type": "long"
},
"like_count": {
"type": "long"
},
"comment_count": {
"type": "long"
},
"rank": {
"type": "double"
},
"location": {
"type": "geo_point"
},
"pub_time": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd HH:mm||yyyy-MM-dd||epoch_millis"
}
}
}
}
テストデータを準備します。
ID | タイトル | タグ | read_count | コメント数 | like_count | ランク | 位置 | パブタイム |
---|---|---|---|---|---|---|---|---|
1 | 台風「ドゥスールイ」が福建省晋江市に上陸し、多くの部門や場所が対応に全力を尽くした | 台風、杜蘇瑞、福建省 | 10000 | 2000年 | 600 | 0 | 118.55199,24.78144 | 2023-07-29 09:47 |
2 | 台風「ドゥスールイ」の影響で、北京では7月29日から8月1日まで大雨が降る見込み | 台風、ドゥ・スルイ、北京 | 1000 | 200 | 60 | 0 | 116.23128,40.22077 | 2023-06-29 14:49:38 |
3 | 杭州市、台風の青色警報信号を解除 | 台風、杭州 | 10 | 2 | 6 | 0.9 | 120.21201,30.2084 | 2020-07-29 14:49:38 |
データを一括追加しますelasticsearch
。
POST _bulk
{
"create": {
"_index": "news", "_id": 1}}
{
"comment_count":600,"id":1,"like_count":2000,"location":[118.55199,24.78144],"pub_time":"2023-07-29 09:47","rank":0.0,"read_count":10000,"tags":["台风","杜苏芮","福建"],"title":"台风“杜苏芮”登陆福建晋江 多部门多地全力应对"}
{
"create": {
"_index": "news", "_id": 2}}
{
"comment_count":60,"id":2,"like_count":200,"location":[116.23128,40.22077],"pub_time":"2023-06-29 14:49:38","rank":0.0,"read_count":1000,"tags":["台风","杜苏芮","北京"],"title":"受台风“杜苏芮”影响 北京7月29日至8月1日将有强降雨"}
{
"create": {
"_index": "news", "_id": 3}}
{
"comment_count":6,"id":3,"like_count":20,"location":[120.21201,30.208],"pub_time":"2020-07-29 14:49:38","rank":0.99,"read_count":100,"tags":["台风","杭州"],"title":"杭州解除台风蓝色预警信号"}
random_score
の使用法
、 、の機能をrandom_score
理解して、デモを直接見てみましょうweight
score_mode
boost_mode
GET /news/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "台风"
}},
"functions": [
{
"random_score": {
},
"weight": 1
},
{
"filter": {
"match": {
"title": "杭州" } },
"weight":42
}
],
"score_mode": "sum",
"boost_mode": "replace"
}
}
}
対応するJAVA
クエリコード:
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(QueryBuilders.matchQuery("title","杭州"));
FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[1];
ScoreFunctionBuilder<RandomScoreFunctionBuilder> randomScoreFilter = new RandomScoreFunctionBuilder();
((RandomScoreFunctionBuilder) randomScoreFilter).seed(2);
filterFunctionBuilders[0] = new FunctionScoreQueryBuilder.FilterFunctionBuilder(randomScoreFilter);
FunctionScoreQueryBuilder query = QueryBuilders.functionScoreQuery(queryBuilder, filterFunctionBuilders).scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.SUM);
SearchSourceBuilder searchSourceBuilder= new SearchSourceBuilder().query(query);
SearchRequest searchRequest= new SearchRequest().searchType(SearchType.DFS_QUERY_THEN_FETCH).indices("news").source(searchSourceBuilder);
SearchResponse response = restClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
String searchSource;
for (SearchHit hit : hits)
{
searchSource = hit.getSourceAsString();
System.out.println(searchSource);
}
検索結果:
このクエリは を使用しますfunction_score
。「Typhoon」を検索するquery
ことで、 2 つのスコアを追加しました。1 つはランダムにスコアを生成するもので、スコアの重みは 1 です。2 つ目は、タイトルに「杭州」がある場合、スコアの重みは次のとおりです。 42、title
functions
random_score
weight
-
random_score
名前が示すとおり、(0,1) の間のランダムなスコアを生成することです。私が考える応用シナリオの 1 つは、製品が必要とするある日、ニュースの見方は人それぞれです。一日を与えてください。random_score
毎回抽出されるデータはランダムであり、誰もが見るニュースは異なりますが、このランダムクエリは実装よりもはるかに簡単で、コストゼロで「千Mysql
人には千の顔がある」を実現しています。 -
weight
これは、生成されたスコアに重みを追加するためです。上記のデモでは、私たちは 1 番目weight=1
と 2 番目weight=42
です。検索結果のスコアから、「杭州は台風の青色の警告信号を解除します」のスコアは 42.40192 であることがわかります。次の場合、重量が 42 倍に増加するため、わずか 0.8194501 になります。 -
score_mode
score_mode
この関数はfunctions
、途中で計算された複数のスコアを集計するものです。たとえば、 yes を使用すると、上で取得したスコアと真ん中で取得した 42 点を加算するsum
ことを意味します。つまり、最初のスコア 42.40192 が生成されます 0.40192さらに42得点を獲得した。デフォルトでは を使用することになっており、合計 6 つの計算方法があります。random_score
filter
random_score
filter
score_mode
multiply
random_score 関数 |
計算 |
---|---|
multiply |
スコアは乗算されます (デフォルト) |
sum |
スコアは合計されます |
avg |
スコアは平均化されます |
first |
一致するフィルターを持つ最初の関数が適用されます |
max |
最大スコアが使用されます |
min |
最小スコアが使用されます |
boost_mode
boost_mode
この機能は、functions
合計スコアとクエリによって取得されたスコアquery
を計算することです。たとえば、使用中のスコアをreplace
フル使用中のfunctions
スコアに置き換えて使用しますquery
。boost_mode
計算方法は合計 6 つあります。
boost_mode 関数 |
採点方法 |
---|---|
multiply |
クエリスコアと関数スコアが乗算されます (デフォルト) |
replace |
関数スコアのみが使用され、クエリスコアは無視されます。 |
sum |
クエリスコアと関数スコアが追加されます |
avg |
平均 |
max |
クエリスコアと関数スコアの最大値 |
min |
クエリスコアと関数スコアの最小値 |
script_score
の使用法
script_score
これは、さまざまな関数を使用してドキュメントに表示されるフィールドを計算し、必要なスコアを計算できることを意味します。
GET /news/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "台风" }
},
"script_score": {
"script": {
"params": {
"readCount": 1,
"likeCount":5,
"commentCount":10
},
"source": "Math.log(params.readCount* doc['read_count'].value +params.likeCount* doc['like_count'].value+params.commentCount* doc['comment_count'].value) "
}
},
"boost_mode": "multiply"
}
}
}
各ニュース記事には阅读数
、点赞数据
、があり评论数
、これら 3 つの指標を使用して記事の人気度を評価するスコアを計算し、query
その人気度とスコアを乗算することで、人気の高い記事を上位に表示することができます。このデモでは、単純な重み付けを使用して記事の人気度を計算します。一般的に、それが阅读数
最大であり、点赞数
次に评论数
最小になります。
記事の人気度 = Log (コメント数 × 10 + いいね数 × 5 + 閲覧数) 記事の人気度 = Log(コメント数\× 10 + いいね数\× 5 + 閲覧数)記事の人気=Log (コメント数_×10+いいね!×5+読み)
ここではデモンストレーションのために、単純に記事の人気度を数えますが、実際はこれよりもはるかに複雑で、記事の種類によって重要性も異なる可能性があります。
field_value_factor
の使用法
field_value_factor
elasticsearch
これは、いくつかの組み込み関数を提供するものとして理解できます。script_score
毎回記述するのがscript_score
あまりにも便利すぎてはなりません。いくつかの組み込み関数があれば、そのまま使用するのがはるかに便利になります。実際に見てみましょうデモ
GET /news/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "台风"
}
},
"field_value_factor": {
"field": "rank",
"factor": 10,
"modifier": "sqrt",
"missing": 1
},
"boost_mode": "multiply"
}
}
}
ここにあるものはfield_value_factor
同等ですscript_score
。sqrt(10 * doc['rank'].value)
ここでの係数は乗算する回数です。デフォルトは 1 回です。missing
そのようなフィールドがない場合、デフォルト値は 1 です。modifier
これは計算関数であり、field
計算されるフィールドです。
modifier
計算機能には以下の種類があります。
modifier 関数 |
採点方法 |
---|---|
none |
フィールド値に乗数を適用しないでください。 |
log |
フィールド値の常用対数を取得します 。この関数は 0 から 1 までの値に使用すると負の値を返し、エラーが発生するため、 log1p 代わりに使用することをお勧めします。 |
log1p |
フィールド値に 1 を加算し、常用対数を計算します。 |
log2p |
フィールド値に 2 を加算し、常用対数を計算します。 |
ln |
Take the natural logarithm of the field value. Because this function will return a negative value and cause an error if used on values between 0 and 1, it is recommended to use ln1p instead. |
ln1p |
Add 1 to the field value and take the natural logarithm |
ln2p |
Add 2 to the field value and take the natural logarithm |
square |
Square the field value (multiply it by itself) |
sqrt |
Take the square root of the field value |
reciprocal |
Reciprocate the field value, same as 1/x where x is the field’s value |
衰减函数Decay functions的使用
衰减函数可以理解成计算文档中某一个字段与给定值的距离,如果距离越近得分就越高,距离越远得分就越低,这个就比较适用于新闻发布时间的衰减了,越久前发布的新闻,得分应该越小,排序越往后。我们直接看Demo
GET /news/_search
{
"query": {
"function_score": {
"query": {
"match": {
"title": "台风"
}
},
"functions": [
{
"gauss": {
"pub_time": {
"origin": "now",
"offset": "7d",
"scale": "60d",
"decay": 0.9
}
}
},
{
"exp": {
"location": {
"origin": {
"lat": 120.21551,
"lon": 30.25308
},
"offset": "50km",
"scale": "50km",
"decay": 0.1
}
}
}
],
"score_mode": "sum",
"boost_mode": "sum"
}
}
}
搜索结果:
衰减函数有3种,分别为gauss
高斯函数、lin
线程函数、exp
对数函数,具体的计算公式可以参考官方文档,这里我们主要理解衰减函数的4个参数作用是什么。
-
origin
例えば、上記のニュースリリース時刻の計算の原点は現在時刻であり、経度および緯度の計算の原点はユーザーの検索位置であるなど、距離の計算の原点として理解できます。 、杭州にいる場合は、origin
杭州の経度と緯度です。 -
offset
このオフセットは、減衰する必要のない距離として理解できます。たとえば、上記のデモでは、距離は7dpub_time
ですoffset
。これは、過去 7 日間にリリースされたニュースを減衰する必要がないことを意味し、スコアは直接的には 1 です。緯度と経度の計算でoffset
50km とは、ユーザーから 50km 以内のニュースは減衰する必要がないことを意味し、50km 以内のニュースは基本的に杭州のローカル ニュースであるため、減衰する必要はありません。 -
scale
これらdecay
2 つのパラメーターについては、3 つの関数の公式の減衰図を参照できます。scale
これは、スコアが元の時間まで減衰したdecay
後の距離を表します。例えば、上記の時間減衰は7日以内のニュースは減衰しないことを意味し、67日前(7d+60d)のニューススコアは0.9、経度緯度減衰は50km以内の距離は減衰しないことを意味します。 、および 100km (50km+50km) の外れ値のスコアは 0.1 です。scale
scale
offset=7d, scale=60d,decay= 0.9
offset=50km, scale=50km,decay= 0.1
要約する
elasticsearch
これfunction_score
により、非常に柔軟なカスタム スコアリング戦略がいくつか提供されます。実際のプロジェクトでは、独自のニーズに応じてこれらのスコアリング戦略を合理的に組み合わせ、独自の検索ニーズを満たすために対応するパラメーターを調整する必要があります。この記事では主に使用方法を紹介し、function_score
次に実際の検索アプリケーションをもとに、よりわかりやすい検索効果を実現するためのこれらの機能の組み合わせや設定方法を紹介します。