NEST:在条件

时间:2017-06-20 11:30:42

标签: c# elasticsearch nest

在我的应用程序中,我将布尔参数传递给一个函数,该函数通过HasChildQuery搜索弹性索引中的某些文档。
如果此布尔值设置为false,我想排除具有特定字段集的文档,当布尔值设置为true时,我不想要第二个条件。

到目前为止,这是我的方法:

Query = new HasChildQuery                                         
{                                                                 
    // ...                               
    Query = new CommonTermsQuery                                  
    {                                                             
        // This Query always needs to be there  
        Field = Nest.Infer.Field<FaqQuestion>(q => q.Content), 
        Query = content                                   
    }                                                             
    && (includeAutoLearnedData ? null : +new TermQuery            
    {                                                             
        // I only want this Query if includeAutoLearnedData is false    
        Field = Nest.Infer.Field<FaqQuestion>(q => q.AutoLearned),  
        Value = false             
    })                                                            
}                                                                 

我的想法是始终生成这样的请求

has_child
|
|__ ...
|
|__ common_terms

并将其扩展为

has_child
|
|__ ...
|
|__ bool
    |
    |__must
    |  |
    |  |__common_terms
    |  
    |__filter
       |
       |__term

如果includeAutoLearnedData为假。
但是对于这种情况的查询似乎是行不通的。

我希望&& (includeAutoLearnedData ? null : +new TermQuery仅在布尔值为false时添加过滤器,并在查询为真时保持未修改

那么在NEST中在特定条件下包含额外过滤查询的正确方法是什么?

编辑
当我从我的ElasticClient获得结果并期望它具有类似

之类的东西时,我设置了一个断点
Valid NEST response built from a successful low level call on POST: /faq/_search
# Audit trail of this API call:
 - [1] HealthyResponse: Node: http://localhost:9200/ Took: 00:00:00.0770000
# Request:
{
    "query": {
        "has_child": {
             "bool": {
                 "must": [{
                     "common_terms": { ... }
                 }],
                 "filter": [{
                     "term": { ... }
                 }]
             }
         }
    }
}

但实际结果是:

# Request:
{}

1 个答案:

答案 0 :(得分:1)

你所拥有的是正确的,你的方法是合理的,但你在输出中看到{}的原因是因为NEST中的无条件查询;实质上,如果查询没有设置某些属性(或者它们被分配null或空字符串),则查询被视为无条件,并且不作为请求的一部分进行序列化。例如,对于term查询,如果

  1. field分配了一个空字符串,或null字符串,表达式或属性
  2. valuenull或空字符串
  3. 然后term查询被认为是无条件的。您可以使用verbatim and strict

    更改此行为

    Verbatim

    单个查询可以标记为逐字,这意味着查询应该按原样发送到Elasticsearch ,即使它是无条件的。

    Strict

    可以将单个查询标记为严格意义,如果它们是无条件的,则抛出异常。当查询必须具有输入值时,这非常有用。

    证明您的方法有效

    void Main()
    {
        var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        var defaultIndex = "default-index";
        var connectionSettings = new ConnectionSettings(pool, new InMemoryConnection())
            .DefaultIndex(defaultIndex)
            .PrettyJson()
            .DisableDirectStreaming()
            .OnRequestCompleted(response =>
                {
                    if (response.RequestBodyInBytes != null)
                    {
                        Console.WriteLine(
                            $"{response.HttpMethod} {response.Uri} \n" +
                            $"{Encoding.UTF8.GetString(response.RequestBodyInBytes)}");
                    }
                    else
                    {
                        Console.WriteLine($"{response.HttpMethod} {response.Uri}");
                    }
    
                    Console.WriteLine();
    
                    if (response.ResponseBodyInBytes != null)
                    {
                        Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
                                 $"{Encoding.UTF8.GetString(response.ResponseBodyInBytes)}\n" +
                                 $"{new string('-', 30)}\n");
                    }
                    else
                    {
                        Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
                                 $"{new string('-', 30)}\n");
                    }
                });
    
        var client = new ElasticClient(connectionSettings);
    
        var includeAutoLearnedData = false;
    
        var request = new SearchRequest<Message>
        {
            Query = new HasChildQuery
            {          
                Type = "child",
                Query = new CommonTermsQuery
                {
                    Field = Infer.Field<Message>(m => m.Content),
                    Query = "commonterms"
                }
                && (includeAutoLearnedData ? null : +new TermQuery
                {
                    Field = Infer.Field<Message>(m => m.Content),
                    Value = "term"
                })
            }
        };
    
        client.Search<Message>(request);
    }
    
    public class Message
    {
        public string Content { get; set; }
    }
    
    includeAutoLearnedDatafalse

    时,

    会生成以下查询

    {
      "query": {
        "has_child": {
          "type": "child",
          "query": {
            "bool": {
              "must": [
                {
                  "common": {
                    "content": {
                      "query": "commonterms"
                    }
                  }
                }
              ],
              "filter": [
                {
                  "term": {
                    "content": {
                      "value": "term"
                    }
                  }
                }
              ]
            }
          }
        }
      }
    }
    

    当它是true

    {
      "query": {
        "has_child": {
          "type": "child",
          "query": {
            "common": {
              "content": {
                "query": "commonterms"
              }
            }
          }
        }
      }
    }
    

    (我注意到我们在 latest documentation 中缺少关于无条件查询的部分。会添加一个!)