elasticsearch.net(NEST)中的等效linq查询

时间:2018-12-19 15:28:36

标签: c# .net linq elasticsearch nest

我的弹性文档类型如下:

public class ProductDto
{
   public Int64 Id { get; set; }

   public String Title{ get; set; }

   public bool Visible { get; set; }

   public IList<ProductSupplierDto> ProductSuppliers { get; set; }
}

public class ProductSupplierDto
{
   public Int64 Id { get; set; }

   public String Title{ get; set; }

   public bool Enabled { get; set; }
}

如何使用Nest libray在linq查询下编写内容:

var products = db.products.where(p=>  p.Visible 
                                   && p.ProductSuppliers.Any(ps=>ps.Enabled)
                                 ).ToList();

在嵌套库中,我有以下查询:

var baseQuery = Query<ProductDto>.Term(qt => qt.Field(f => 
                                      f.Visible).Value(true));

如何在baseQuery中添加产品供应商过滤器?

我使用此方法创建索引:

    private async Task CreateIndexIfItDoesntExist<T>(string index) where T: class
    {
        if (!this.client.IndexExists(index).Exists)
        {
            var indexDescriptor = new CreateIndexDescriptor(index)
                            .Settings(x => x.NumberOfReplicas(0))
                            .Mappings(mappings => mappings
                                .Map<T>(m => m.AutoMap()));

            await this.client.CreateIndexAsync(index, i => indexDescriptor);

       // Max out the result window so you can have pagination for >100 pages
           await this.client.UpdateIndexSettingsAsync(index, ixs => ixs
             .IndexSettings(s => s
                 .Setting("max_result_window", int.MaxValue)));


        }
    }

并像这样调用:

await CreateIndexIfItDoesntExist<ProductDto>("products");

索引数据方法:

    private async Task<IndexResult> IndexDocuments<T>(T[] datas, string index) where T:class
    {
        int batchSize = 1000; // magic
        int totalBatches = (int)Math.Ceiling((double)datas.Length / batchSize);

        for (int i = 0; i < totalBatches; i++)
        {
            var response = await this.client.IndexManyAsync(datas.Skip(i * batchSize).Take(batchSize), index);

            if (!response.IsValid)
            {
                return new IndexResult
                {
                    IsValid = false,
                    ErrorReason = response.ServerError?.Error?.Reason,
                    Exception = response.OriginalException
                };
            }
            else
            {
                Debug.WriteLine($"Successfully indexed batch {i + 1}");
            }
        }

        return new IndexResult
        {
            IsValid = true
        };
    }

2 个答案:

答案 0 :(得分:1)

ProductSupplierDto中的

ProductSuppliers将被映射为具有自动映射的object类型,因此以下查询将实现您想要的

var client = new ElasticClient();

var searchResponse = client.Search<ProductDto>(s => s
    .Query(q => +q
        .Term(f => f.Visible, true) && +q
        .Term(f => f.ProductSuppliers[0].Enabled, true)
    )    
);  

这会生成以下查询

{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "visible": {
              "value": true
            }
          }
        },
        {
          "term": {
            "productSuppliers.enabled": {
              "value": true
            }
          }
        }
      ]
    }
  }
}

几点

  1. 查询使用operator overloading on queries将它们组合在一起并生成在过滤器上下文中执行的查询(在这种情况下,是bool查询filter子句)。由于文档匹配或不匹配,因此无需计算匹配的相关性得分。
  2. f => f.ProductSuppliers[0].Enabled是用于获取字段路径的表达式。这并不意味着”从Enabled的第一项中获取ProductSuppliers的值” ,而是”获取到Enabled字段的路径ProductSuppliers属性中的所有项目” 。只能使用 进入集合中的索引器,以便能够访问ProductSupplierDto类型的属性。

您可能想要consider mapping ProductSuppliers as a nested type,以便能够在ProductSuppliers集合中的各个项目的属性之间进行查询。将ProductSuppliers映射为nested类型后,查询将为

var searchResponse = client.Search<ProductDto>(s => s
    .Query(q => +q
        .Term(f => f.Visible, true) && +q
        .Nested(n => n
            .Path(p => p.ProductSuppliers)
            .Query(nq => nq
                .Term(f => f.ProductSuppliers[0].Enabled, true)
            )
        )           
    )    
);

答案 1 :(得分:-1)

像这样吗?

  QueryContainer baseQuery = Query<ProductDto>.Term(qt => qt.Field(f =>
                                   f.Visible).Value(true));
        baseQuery &= Query<ProductDto>.Term(qt => qt.Field(o => o.ProductSuppliers.Select(a => a.Enabled)).Value(true));

        client.Search<ProductDto>(o => o
           .From(0)
           .Size(10)
           .Query(a => baseQuery));