Elasticsearch 有条件匹配所有标签、类别和关键字

问题描述 投票:0回答:1

我正在尝试使用 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": "ナイトフィーバー"
      }
    }

我想要实现的是:

  1. 当没有指定关键字时,它会尝试匹配以下条件: 一个)。

    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 排序。

  2. 当指定关键字时,它将匹配与上面相同的条件(无关键字),此外,它还会匹配任何标题(title,title_en,title_cn,title_de,title_ja),以及任何歌手的全名,以及任何带有名称的标签,以及任何带有名称的类别

简单来说,这些条件都是有条件的,取决于是否提供了某些相应的参数。

我不确定如何将所有这些条件“链接”在一起。

有什么想法吗?

elasticsearch
1个回答
0
投票

要构建满足您要求的 Elasticsearch 查询,您需要使用

bool
must
should
filter
子句的组合来链接您想要的所有条件一起。

我已经提供了您所询问的案例的 DSL 示例:

1. 基本查询(无关键字)

{
  "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"
      }
    }
  ]
}

2. 关键字搜索(使用关键字)

{
  "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"
      }
    }
  ]
}

说明:

  1. 基本查询(使用

    bool
    filter
    进行
    must
    查询)
    :

    • must
      :用于添加所需条件(如关键字搜索)。当没有提供关键字时,可以为空。
    • filter
      :用于必须为真但不影响评分的条件。这是我们应用持续时间、标签、类别、歌手和质量过滤器的地方。
  2. 有条件地处理参数:

    • 如果未提供参数(如标签、类别、歌手或品质),您可以从查询中排除相应的过滤器块。在您的应用程序代码中,您可以根据提供的输入动态构建查询。
  3. 排序

    • 首先按
      ratings
      排序,然后按
      favorites
      排序,最后通过自定义脚本计算
      votesUp / (votesUp + votesDown)
      的比率来获得受欢迎程度得分。
  4. 关键字搜索:

    • 提供关键字时,会在 multi_match
       子句中添加 
      must
       查询。它跨多个字段进行搜索(
      title
      title_en
      title_cn
      等)并匹配任何歌手的全名、标签名称和类别名称。

.NET 客户端中的条件查询构造

在 .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" }
    });
}

这将允许您根据可用的输入参数构建动态查询。

© www.soinside.com 2019 - 2024. All rights reserved.