简体   繁体   中英

Nest queries with field priority and filter query

I am trying build a search functionality with ElasticSearch using Nest. What I need is following:

  • I have product table and I indexed is as below:

     foreach (var product in products) { Product product = new Product(product.ProductId, product.Name, product.Number, product.Description); ElasticClient.Index(productes); } 
  • Then I execute following queries:

    1. This works fine. I get results.

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

      Both none of the below queries work. Why? What am I doing wrong?

    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)); 

I would like to first of all understand why queries with filter don't work for me. Finally, I want to achieve a query that searches a given keyword and prioritizes results based on which field (column, property) it was found in.

So if keyword was in the "name" field, it should be returned at the top. So respectively, "Name", "Number", "Description". How can I achieve such a query?

EDIT: I tried the query below but it doesn't return anything.

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))));

Below some samples data; when I send "2000" as keyword, I get following results with 1. query but others will not return anything.

在此处输入图片说明

The main reason why the first query returns results and the others don't is because the first query is a query_string and the input keyword (eg 2000 ) will be analyzed and matched with any of your fields (which are also analyzed). This is not the case of the second, third and fourth queries because you're using a term query/filter where the input is not analyzed and instead matched as is .

If we take the first document (id=13), the name field will be analyzed and indexed as the following tokens: dr , 2000 , 12k (in lowercase!) as can be seen with the following command:

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

So when searching for 2000 (or dr or 12k ) in a query_string query, you'll find that document. Searching for the term 2000 won't yield anything though, which is expected when using term query/filter that work for exact matching.

As for your second question on boosting fields, the reason that query returns nothing is maybe because the field names are lowercased by default (default behavior of NEST). You should make sure to use lowercase field names.

UPDATE

If you need to perform exact matching, I advise to change your field mappings to multi-field string fields with an analyzed and a not_analyzed field.

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

Then you can query the name field with query_string when you need like behavior and the name.raw field when you need exact match behavior with term query/filter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM