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

Equivalent linq query in elasticsearch.net(NEST)

我在 elastic 中有以下文件类型:

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 库编写以下 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
        };
    }

是这样的吗?

  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));
ProductSuppliers 中的

ProductSupplierDto 将被映射为具有自动映射的 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 是获取字段路径的表达式。不是"get the value of Enabled from the first item in ProductSuppliers",而是"get the path to the Enabled field of all items in the ProductSuppliers property"。此处集合中的索引器 能够访问 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)
            )
        )           
    )    
);