【问题标题】:Nest queries with field priority and filter query具有字段优先级的嵌套查询和过滤查询
【发布时间】:2015-09-01 17:51:22
【问题描述】:

我正在尝试使用 Nest 使用 ElasticSearch 构建搜索功能。我需要的是:

  • 我有产品表,我索引如下:

    foreach (var product in products) {
        Product product = new Product(product.ProductId, product.Name, product.Number, product.Description);   
        ElasticClient.Index(productes);
    }
    
  • 然后我执行以下查询:

    1. 这很好用。我得到了结果。

      var results = ElasticClient.Search<Product>(body => body.Query(query => query.QueryString(qs => qs.Query(key))).Size(20));
      

      以下查询均无效。为什么?我做错了什么?

    2. -

      var results = ElasticClient.Search<Product>(body => body.Filter(filter => filter.Term(x => x.Name, key)).Take(1000));
      
    3. -

      var results = ElasticClient.Search<Product>(s => s
          .From(0)
          .Size(15)
          .Query(q => q
              .Term(p => p.Name, key)));
      
    4. -

      var results = ElasticClient.Search<Product>(body => body.Query(query => query.ConstantScore(csq => csq.Filter(filter => filter.Term(x => x.Name, key.ToLower())))).Take(1000));
      

我想首先了解为什么带有过滤器的查询对我不起作用。最后,我想实现一个查询,它可以搜索给定的关键字,并根据在哪个字段(列、属性)中找到结果来确定结果的优先级。

因此,如果关键字在“名称”字段中,则应在顶部返回。所以分别是“名称”、“编号”、“描述”。我怎样才能实现这样的查询?

编辑:我尝试了下面的查询,但它没有返回任何内容。

var results = ElasticClient.Search<Product>(body => body
    .Query(q => q
        .QueryString(qs => qs
            .OnFieldsWithBoost(d => d
                .Add(entry => entry.Name, 5.0)
                .Add(entry => entry.Number, 3.0)
                .Add(entry => entry.Description, 2.0))
            .Query(key))));

下面是一些样本数据; 当我发送“2000”作为关键字时,我得到以下结果 1. 查询但其他人不会返回任何内容。

【问题讨论】:

  • 您能否分享一些带有“名称”字段示例值的示例文档?
  • @bittusarkar 我添加了一些示例值,够了吗?
  • 在您上面的查询中,您对key 变量使用了什么?你能分享一下你正在搜索的关键字吗?
  • @Val 正如我在那里写的那样,我使用“2000”作为关键字,第一个查询返回结果,但其他查询不返回。

标签: c# elasticsearch nest


【解决方案1】:

第一个查询返回结果而其他查询不返回结果的主要原因是因为第一个查询是query_string,并且输入关键字(例如2000)将被分析并与您的任何字段匹配(其中也进行了分析)。这不是第二个、第三个和第四个查询的情况,因为您使用的是term 查询/过滤器,其中输入没有被分析,而是按原样匹配。

如果我们取第一个文档(id=13),name 字段将被分析并索引为以下标记:dr200012k(小写!)如图所示使用以下命令:

curl -XGET 'localhost:9200/_analyze?pretty&analyzer=standard' -d 'DR-2000 (12k)'

{
  "tokens" : [ {
    "token" : "dr",
    "start_offset" : 0,
    "end_offset" : 2,
    "type" : "<ALPHANUM>",
    "position" : 1
  }, {
    "token" : "2000",
    "start_offset" : 3,
    "end_offset" : 7,
    "type" : "<NUM>",
    "position" : 2
  }, {
    "token" : "12k",
    "start_offset" : 9,
    "end_offset" : 12,
    "type" : "<ALPHANUM>",
    "position" : 3
  } ]
}

因此,在query_string 查询中搜索2000(或dr12k)时,您会找到该文档。但是,搜索术语 2000 不会产生任何结果,这在使用用于精确匹配的 term 查询/过滤器时是预期的。

关于提升字段的第二个问题,查询不返回任何内容的原因可能是因为字段名称are lowercased by default(NEST 的默认行为)。您应该确保使用小写的字段名称。

更新

如果您需要执行精确匹配,我建议您将字段映射更改为 multi-field string fields,并带有 analyzednot_analyzed 字段。

{
  "product" : {
    "properties" : {
      "name" : {
        "type" : "string",
        "index" : "analyzed",
        "fields" : {
          "raw" : {"type" : "string", "index" : "not_analyzed"}
        }
      }
    }
  }
}

然后,当您需要 like 行为时,您可以使用query_string 查询name 字段,而当您需要使用term 查询/过滤器的精确匹配行为时,您可以使用name.raw 字段。

【讨论】:

  • 我实际上是在使用这一行 settings.SetDefaultPropertyNameInferrer(p => p);它对小写情况没有帮助。我读到如果我使用这个设置,它应该按原样解释,而不是小写。
  • 好的,不过,您是否得到了您期望的第一个答案的信息?
  • 所以基本上,术语过滤器是完全匹配的,就像在 sql = equal 子句中一样,而查询字符串就像“like %key%” where 子句,如果把它放在 sql 术语中。你是这么说的吗?
  • 但我试图通过给出确切的单词作为例如 DR-2000(12k) 来执行第二个查询,但它没有工作。我什至将它从名称更改为要搜索的数字字段,我给了 10002,这是 Id=13 的数字。仍然没有返回。
  • 是的,您必须重新索引您的数据,和/或更新您的所有文档,这是同样的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-04
  • 2011-12-24
  • 1970-01-01
  • 2012-01-17
  • 1970-01-01
  • 2014-02-13
  • 1970-01-01
相关资源
最近更新 更多