You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Elastic.Clients.Elasticsearch C#定义父子关系

使用Elastic.Clients.Elasticsearch实现父子文档关系

一、改造实体类

适配新客户端库的实体类定义如下,核心是替换命名空间并使用新的JoinField类型:

using Elastic.Clients.Elasticsearch.Attributes;
using Elastic.Clients.Elasticsearch.Mapping;

public abstract class BaseDocument
{
    public virtual int Id { get; set; }
    public int ParentId { get; set; }

    // 新客户端的Join字段类型
    public JoinField JoinField { get; set; }

    public BaseDocument() { }
}

[ElasticsearchType(RelationName = "product")]
public class Product : BaseDocument
{
    [Keyword]
    public string Name { get; set; }

    public decimal Price { get; set; }
}

[ElasticsearchType(RelationName = "stock")]
public class Stock : BaseDocument
{
    [Keyword]
    public string Country { get; set; }

    public int Quantity { get; set; }
}

[ElasticsearchType(RelationName = "supplier")]
public class Supplier : BaseDocument
{
    [Keyword]
    public string SupplierDescription { get; set; }
}

[ElasticsearchType(RelationName = "category")]
public class Category : BaseDocument
{
    [Keyword]
    public string CategoryDescription { get; set; }
}

二、创建索引并定义父子映射

以下是对应原NEST代码的索引创建实现,适配新客户端的API语法:

var createIndexResponse = _elasticClient.Indices.Create(_indexName, c => c
    .Settings(s => s
        .NumberOfReplicas(0)
        .RefreshInterval(-1)
        .NumberOfShards(5))
    .Map<BaseDocument>(m => m
        .RoutingField(r => r.Required(true)) // 强制路由,确保父子文档存储在同一分片
        .AutoMap<Product>()
        .AutoMap<Category>()
        .AutoMap<Supplier>()
        .AutoMap<Stock>()
        // 手动配置Product的Name字段(对应原代码的Text类型定义)
        .Properties(props => props
            .Text(t => t
                .Name(p => p.Name)
                .Analyzer("default")
                .Fields(f => f.Keyword(k => k.Name("keyword"))))
            // 定义父子关系映射
            .Join(j => j
                .Name(p => p.JoinField)
                .Relations(r => r
                    // 指定Product为父类型,关联category、supplier、stock三个子类型
                    .Add<Product>(childRelations => childRelations
                        .Children("category", "supplier", "stock"))))));

三、父子文档写入示例

写入父文档(Product)

var product = new Product
{
    Id = 1,
    Name = "Sample Phone",
    Price = 2999.99m,
    JoinField = JoinField.Create<Product>() // 标记为父文档类型
};

var indexProductResponse = _elasticClient.Index(product, i => i
    .Routing(product.Id.ToString())
    .Index(_indexName));

写入子文档(Stock)

var stock = new Stock
{
    Id = 1001,
    ParentId = 1,
    Country = "CN",
    Quantity = 100,
    JoinField = JoinField.LinkTo<Product>(1) // 指定关联的父文档ID和类型
};

var indexStockResponse = _elasticClient.Index(stock, i => i
    .Routing(stock.ParentId.ToString()) // 路由值必须与父文档一致
    .Index(_indexName));

关键注意事项

  • 父子文档必须使用相同的路由值(通常用父文档ID),否则无法建立关联,开启RoutingField.Required(true)可以强制校验这一点。
  • 子类型名称必须与实体类[ElasticsearchType(RelationName)]指定的名称完全匹配。
  • 新客户端的JoinField提供了Create<TParent>和LinkTo<TParent>(parentId)两个便捷方法,分别用于创建父文档和子文档的关联字段值。

内容的提问来源于stack exchange,提问作者user2932893

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 01:17:49