我正在尝试使用 Elasticsearch 9.15 构建音乐搜索功能。
我目前正在使用.NET 客户端。我很高兴通过 DSL 了解它的样子,这样我就可以将它复制到 .NET。
每首音乐都可以像下面的json:
{
"_source": {
"duration": 258,
"ratings": 67.8,
"addedTime": "2024-09-25T16:22:53.0427917+10:00",
"createdTime": "2024-09-25T16:22:53.0447736+10:00",
"favorites": 9999,
"votesUp": 7778,
"votesDown": 4212,
"languageId": 2,
"tags": [
{
"tagId": 3,
"languageId": 2,
"name": "Australia"
},
{
"tagId": 2,
"languageId": 2,
"name": "Good"
}
],
"categories": [
{
"categoryId": 1,
"languageId": 2,
"name": "Love"
},
{
"categoryId": 3,
"languageId": 2,
"name": "Soft"
}
],
"singers": [
{
"singerId": 2,
"fullName": "Bee Gees",
"firstName": "Bee",
"lastName": "Gees"
}
],
"qualities": [
{
"qualityId": 2,
"resolution": 160
},
{
"qualityId": 3,
"resolution": 320
},
{
"qualityId": 4,
"resolution": 640
}
],
"id": "161d12b7-bcb6-40ab-9ea9-44683f15be45",
"uniqueId": 1,
"providerId": 1,
"sourceKey": "BeeGees0001",
"title": "Night Fever",
"title_en": "Night Fever",
"title_cn": "夜热",
"title_de": "Nachtfieber",
"title_ja": "ナイトフィーバー"
}
}
我想要实现的是:
当没有指定关键字时,它会尝试匹配以下条件: 一个)。
duration
,以秒为单位,应该在一个范围内(minDuration参数<= duration
<= maxDuration parameter)
b). it should match all the tags, if tags parameter provided
c). it should match all the categories, if categories parameter provided
c). it should match all singers, if singers parameter provided
d). it should match all the sound qualities, if qualities parameter provided
然后,它应该按
ratings
desc 排序,然后按 favorites
desc 排序,然后按 votesUp
/ (votesDown
+ votesUp
) desc 排序。
当指定关键字时,它将匹配与上面相同的条件(无关键字),此外,它还会匹配任何标题(title,title_en,title_cn,title_de,title_ja),以及任何歌手的全名,以及任何带有名称的标签,以及任何带有名称的类别
简单来说,这些条件都是有条件的,取决于是否提供了某些相应的参数。
我不确定如何将所有这些条件“链接”在一起。
有什么想法吗?
要构建满足您要求的 Elasticsearch 查询,您需要使用
bool
、must
、should
和 filter
子句的组合来链接您想要的所有条件一起。
我已经提供了您所询问的案例的 DSL 示例:
{
"query": {
"bool": {
"must": [],
"filter": [
{
"range": {
"duration": {
"gte": "{{minDuration}}",
"lte": "{{maxDuration}}"
}
}
},
{
"terms": {
"tags.name": ["{{tag1}}", "{{tag2}}"]
}
},
{
"terms": {
"categories.name": ["{{category1}}", "{{category2}}"]
}
},
{
"terms": {
"singers.fullName": ["{{singer1}}", "{{singer2}}"]
}
},
{
"terms": {
"qualities.resolution": [160, 320, 640]
}
}
]
}
},
"sort": [
{ "ratings": { "order": "desc" }},
{ "favorites": { "order": "desc" }},
{
"_script": {
"type": "number",
"script": {
"source": "doc['votesUp'].value / (doc['votesUp'].value + doc['votesDown'].value)"
},
"order": "desc"
}
}
]
}
{
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "{{keyword}}",
"fields": ["title", "title_en", "title_cn", "title_de", "title_ja", "singers.fullName", "tags.name", "categories.name"],
"type": "best_fields"
}
}
],
"filter": [
{
"range": {
"duration": {
"gte": "{{minDuration}}",
"lte": "{{maxDuration}}"
}
}
},
{
"terms": {
"tags.name": ["{{tag1}}", "{{tag2}}"]
}
},
{
"terms": {
"categories.name": ["{{category1}}", "{{category2}}"]
}
},
{
"terms": {
"singers.fullName": ["{{singer1}}", "{{singer2}}"]
}
},
{
"terms": {
"qualities.resolution": [160, 320, 640]
}
}
]
}
},
"sort": [
{ "ratings": { "order": "desc" }},
{ "favorites": { "order": "desc" }},
{
"_script": {
"type": "number",
"script": {
"source": "doc['votesUp'].value / (doc['votesUp'].value + doc['votesDown'].value + 1)"
},
"order": "desc"
}
}
]
}
基本查询(使用
bool
和 filter
进行must
查询):
must
:用于添加所需条件(如关键字搜索)。当没有提供关键字时,可以为空。filter
:用于必须为真但不影响评分的条件。这是我们应用持续时间、标签、类别、歌手和质量过滤器的地方。有条件地处理参数:
排序:
ratings
排序,然后按 favorites
排序,最后通过自定义脚本计算 votesUp / (votesUp + votesDown)
的比率来获得受欢迎程度得分。关键字搜索:
multi_match
子句中添加
must
查询。它跨多个字段进行搜索(title
、title_en
、title_cn
等)并匹配任何歌手的全名、标签名称和类别名称。在 .NET 客户端中,您可以通过检查每个参数(例如关键字、标签、歌手)是否存在并包含相应的过滤器或
multi_match
子句(如果该参数存在)来以编程方式构造此查询。
例如,您可以使用构建器模式或有条件地在 C# 中添加过滤器/必须查询,如下所示:
var searchRequest = new SearchRequest("music_index")
{
Query = new BoolQuery
{
Must = new List<QueryContainer>(),
Filter = new List<QueryContainer>
{
new RangeQuery
{
Field = "duration",
GreaterThanOrEqualTo = minDuration,
LessThanOrEqualTo = maxDuration
}
}
},
Sort = new List<ISort>
{
new FieldSort { Field = "ratings", Order = SortOrder.Descending },
new FieldSort { Field = "favorites", Order = SortOrder.Descending },
new ScriptSort
{
Type = "number",
Script = new InlineScript("doc['votesUp'].value / (doc['votesUp'].value + doc['votesDown'].value)"),
Order = SortOrder.Descending
}
}
};
// Add filters conditionally based on provided parameters
if (tags != null && tags.Any())
{
searchRequest.Query.Filter.Add(new TermsQuery { Field = "tags.name", Terms = tags });
}
if (keyword != null)
{
searchRequest.Query.Must.Add(new MultiMatchQuery
{
Query = keyword,
Fields = new[] { "title", "title_en", "title_cn", "title_de", "title_ja", "singers.fullName", "tags.name", "categories.name" }
});
}
这将允许您根据可用的输入参数构建动态查询。