如何跳过索引特定 属性,但在 Elasticsearch 和 NEST 中查询时仍然检索其内容?

How can I skip indexing a specific property, but still retrieve its contents when querying in Elasticsearch and NEST?

给定这个索引模型 class:

public class ProductIndexModel
{
    public Guid Id { get; set; }
    public DateTime Created { get; set; }
    public string Name { get; set; }
    public JObject DynamicContent { get; set; }
}

我正在努力做到以下几点:

我不索引 DynamicContent 属性 的原因是,它是一个 json-blob,属性-路径之间偶尔会发生冲突,即不同类型(例如对象与字符串、整数与字符串等)。例如,尝试用 2 个对象索引路径 /dynamiccontent.id,其中值分别为 int 和 string 类型可能会给我:

error: Type: mapper_parsing_exception Reason: "failed to parse [dynamiccontent.id]" CausedBy: Type: json_parse_exception Reason: "Current token (START_OBJECT) not numeric, can not use numeric value accessors

我是这样创建索引的:

var createIndexResponse = await _elasticClient.CreateIndexAsync(indexName, c => c
    .InitializeUsing(settingsState)
    .Mappings(ms => ms
        .Map<ProductIndexModel>(m => m
            .AutoMap()
        )
    )
);

其中 settingsState 属于 Nest.IndexState 类型,带有一些分词器等等,这与问题无关。

ISearchRequest SearchRequest(SearchDescriptor<ProductIndexModel> x) => x
    .Index(indexName)
    .Query(q => q.Bool(bq => bq.Filter(filters)))
    .From(filter.Offset)
    .Size(filter.PageSize)
;

var searchResponse = await _elasticClient.SearchAsync<ProductIndexModel>(SearchRequest);

其中 filters 是一个动态构造的通用过滤器列表,用于减少结果。

所以我想保持 DynamicContent 未编入索引,但仍然能够在查询时获取其(原始)内容。

我试图用 Nest.IgnoreAttribute 注释 DynamicContent ,但完全没有注释,因此在检索时导致空值。关于如何使用 NEST "store" 值而不是索引它的任何建议?

由于 DynamicContent 是 Json.NET JObject 类型,如果您使用的是 NEST 6.x,则需要 hook up the JsonNetSerializer 才能正确索引 JObject.

的实例

连接此序列化程序后,您可以使用 [Object(Enabled = false)] 为模型添加属性,这会设置 enabled=false for the field,这意味着 属性 会保留在 _source 中但不会被解析或索引。

特别是 JObject,NEST 的自动映射(在映射时需要将属性考虑在内)将为 JObject 生成一个大的 "properties" 对象,这是完全不必要的,因为该字段不会被解析或索引。在这种特殊情况下,流畅映射将是比属性映射更好的选择。这是一个例子:

private static void Main()
{
    var defaultIndex = "default_index";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    var settings = new ConnectionSettings(pool, JsonNetSerializer.Default)
        .DefaultIndex(defaultIndex)
        .DefaultTypeName("_doc");

    var client = new ElasticClient(settings);

    if (client.IndexExists(defaultIndex).Exists)
        client.DeleteIndex(defaultIndex);

    var createIndexResponse = client.CreateIndex(defaultIndex, c => c
        .Mappings(m => m
            .Map<ProductIndexModel>(mm => mm
                .AutoMap() // <-- automap
                .Properties(p => p
                    .Object<JObject>(o => o
                        .Name(n => n.DynamicContent) <-- override the automap inferred mapping for DynamicContent
                        .Enabled(false)
                    )
                )
            )
        )
    );

    var indexResponse = client.Index(new ProductIndexModel
    {
        Id = Guid.NewGuid(),
        Created = DateTime.UtcNow,
        Name = "foo",
        DynamicContent = new JObject 
        {
            { "prop1", "value1" },
            { "prop2", new JArray(1, 2, 3, 4) }
        }
    }, i => i.Refresh(Refresh.WaitFor));

    var searchResponse = client.Search<ProductIndexModel>(s => s
        .MatchAll()
    );
}

public class ProductIndexModel
{
    public Guid Id { get; set; }
    public DateTime Created { get; set; }
    public string Name { get; set; }
    [Object(Enabled = false)]
    public JObject DynamicContent { get; set; }
}