首页 > 解决方案 > NEST 会在 elasticsearch 中还是在客户端中进行项目?

问题描述

如果我有一个在elasticsearch中索引的复杂文档并使用DTO查询它,在将数据发送到C#客户端之前,是否会在elasticsearch中应用DTO所需字段的投影,或者发送完整的源代码,而C#将用它来水合DTO?

var response = await elasticClient.SearchAsync<TDto>(searchRequest);

基本上,我需要知道我是否可以简单地要求 aTDto而不必担心ComplexDocument被索引的较大数据量,或者我是否必须在 中指定Source包含/排除searchRequest以获得最佳性能。

标签: c#performanceelasticsearchnestdto

解决方案


默认情况下,Elasticsearch 将发送回_source每个搜索命中的完整文档。您可以使用源过滤_source指定要包含/排除的字段

var client = new ElasticClient();

var searchResponse = client.Search<ComplexDocument>(s => s
    .Source(sf => sf
        .Includes(i => i
            .Field(f => f.Path)
            .Field(f => f.Content)
        )
        .ExcludeAll()
    )
);

foreach(var source in searchResponse.Documents)
{
    var path = source.Path;
}

发送

{
    "_source": {
        "excludes": ["*"],
        "includes": ["path", "content"]
    }
}

_source或者你可以要求根本不回来

var searchResponse = client.Search<ComplexDocument>(s => s
    .Source(false)
);

_source使用源过滤,在 Elasticsearch 端完全读取存储字段,并应用过滤。这通常很好,但如果_source是一个巨大的文档,并且您只想返回一个字段子集来响应搜索,您可能会决定使用存储字段

顾名思义,存储字段是单独存储的字段_source(通过store:true在其映射中指定)并且可以在搜索响应中返回

var searchResponse = client.Search<ComplexDocument>(s => s
    .StoredFields(f => f
        .Field(ff => ff.Path)
    )
);

foreach(var fields in searchResponse.Fields)
{
    var path = fields.ValueOf<ComplexDocument, string>(f => f.Path);
}

"fields"每次点击时,都会在一个属性中返回存储的字段。

如果我有一个在elasticsearch中索引的复杂文档并使用DTO查询它,在将数据发送到C#客户端之前,是否会在elasticsearch中应用DTO所需字段的投影,或者发送完整的源代码,而C#将用它来水合DTO?

总之,Elasticsearch 将返回完整的_source,NEST 会将匹配的属性映射_source到 DTO 的属性。默认情况下, NEST将 JSON 中的驼峰式属性映射到 POCO 属性。如果您想通过网络传输更少,请查看源过滤。您可能会封装该功能以在请求中仅包含 DTO 中的字段作为扩展方法SearchDescriptor<TInferDocument>

public class ComplexDocument
{
    public int Id { get; set; }
    public string Path { get; set; }
    public string Content { get; set; }
    public Attachment Attachment { get; set; }
}

public class SimpleDTO
{
    public string Path { get; set; }
}

public static class SearchDescriptorExtensions
{
    public static SearchDescriptor<TInferDocument> SourceIncludesDto<TInferDocument, TDocument>(this SearchDescriptor<TInferDocument> descriptor) 
        where TInferDocument : class
        where TDocument : class
        {
            // TODO: cache this :)
            Fields fields = typeof(TDocument).GetProperties();

            return descriptor.Source(s => s
                .Includes(f => f
                    .Fields(fields)
                )
            );
        }
}

ISearchResponse<SimpleDTO> searchResponse = 
    client.Search<ComplexDocument, SimpleDTO>(s => s
        .SourceIncludesDto<ComplexDocument, SimpleDTO>()
    );

发送

{
    "_source": {
        "includes": ["path"]
    }
}

推荐阅读