使用NEST ElasticSearch客户端获取不同的值

时间:2015-02-23 15:26:17

标签: c# .net elasticsearch nest

我使用NEST客户端在我的.NET应用程序中使用Elastic Search构建产品搜索引擎,并且有一件事我遇到了麻烦。获得一组独特的价值观。

我搜索的产品有数千种,但当然我一次只能向用户返回10或20种产品。为此,分页工作正常。但除了这个主要结果,我想向我的用户显示在完整搜索中找到的品牌列表,以呈现这些用于过滤。

我已经读到我应该使用条款聚合。但是,我无法获得比这更好的东西。而这仍然没有真正给我我想要的东西,因为它分裂了像#20; 20世纪福克斯"分成3个单独的值。

    var brandResults = client.Search<Product>(s => s
         .Query(query)
         .Aggregations(a => a.Terms("my_terms_agg", t => t.Field(p => p.BrandName).Size(250))
         )
     );

    var agg = brandResult.Aggs.Terms("my_terms_agg");

这甚至是正确的方法吗?或者应该使用完全不同的东西?而且,我怎样才能获得正确,完整的价值观? (不按空格划分..但我想这就是当你要求列出“条款”时所得到的内容

如果您在MS SQL中执行此操作,我想要的是

SELECT DISTINCT BrandName FROM [Table To Search] WHERE [Where clause without paging]

2 个答案:

答案 0 :(得分:4)

你想要的是一个术语聚合。您遇到的问题是ES正在拆分字段&#34; BrandName&#34;在结果中它正在返回。这是ES中字段的预期默认行为。

我建议您将BrandName更改为&#34; Multifield&#34;,这将允许您搜索所有各个部分,以及在&#34; Not Analyzed&#上执行术语聚合34; (又名完整的&#34; 20世纪福克斯&#34;)一词。

以下是ES的文档。

https://www.elasticsearch.org/guide/en/elasticsearch/reference/0.90/mapping-multi-field-type.html

[UPDATE] 如果您使用的是ES版本1.4或更高版本,则多字段的语法现在略有不同。

https://www.elasticsearch.org/guide/en/elasticsearch/reference/current/_multi_fields.html#_multi_fields

这是一个完整的工作样本,说明了ES 1.4.4中的要点。请注意,映射指定了一个&#34; not_analyzed&#34;该领域的版本。

PUT hilden1

PUT hilden1/type1/_mapping
{
  "properties": {
    "brandName": {
      "type": "string",
      "fields": {
        "raw": {
          "type": "string",
          "index": "not_analyzed"
        }
      }
    }
  }
}

POST hilden1/type1
{
  "brandName": "foo"
}

POST hilden1/type1
{
  "brandName": "bar"
}

POST hilden1/type1
{
  "brandName": "20th Century Fox"
}

POST hilden1/type1
{
  "brandName": "20th Century Fox"
}

POST hilden1/type1
{
  "brandName": "foo bar"
}

GET hilden1/type1/_search
{
  "size": 0, 
  "aggs": {
    "analyzed_field": {
      "terms": {
        "field": "brandName",
        "size": 10
      }
    },
    "non_analyzed_field": {
      "terms": {
        "field": "brandName.raw",
        "size": 10
      }
    }    
  }
}

上次查询的结果:

{
   "took": 3,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 5,
      "max_score": 0,
      "hits": []
   },
   "aggregations": {
      "non_analyzed_field": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            {
               "key": "20th Century Fox",
               "doc_count": 2
            },
            {
               "key": "bar",
               "doc_count": 1
            },
            {
               "key": "foo",
               "doc_count": 1
            },
            {
               "key": "foo bar",
               "doc_count": 1
            }
         ]
      },
      "analyzed_field": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            {
               "key": "20th",
               "doc_count": 2
            },
            {
               "key": "bar",
               "doc_count": 2
            },
            {
               "key": "century",
               "doc_count": 2
            },
            {
               "key": "foo",
               "doc_count": 2
            },
            {
               "key": "fox",
               "doc_count": 2
            }
         ]
      }
   }
}

请注意,未分析的字段会保留&#34; 20世纪的狐狸&#34;和&#34; foo bar&#34;在分析的领域将它们分解的地方。

答案 1 :(得分:1)

我有类似的问题。我正在显示搜索结果,并希望显示类别和子类别的计数。

您使用聚合是正确的。我也遇到了字符串被标记化的问题(即20世纪的狐狸被拆分) - 这是因为字段被分析了。对我来说,我添加了以下映射(即告诉ES不要分析该字段):

  "category": {
          "type": "nested",
          "properties": {
            "CategoryNameAndSlug": {
              "type": "string",
              "index": "not_analyzed"
            },
            "SubCategoryNameAndSlug": {
              "type": "string",
              "index": "not_analyzed"
            }
          }
        }

正如jhilden建议的那样,如果您出于多种原因(例如搜索和聚合)使用此字段,则可以将其设置为多字段。因此,一方面它可以被分析并用于搜索,另一方面可以不进行聚合分析。