繁体   English   中英

Elasticsearch 6.x 中结合Join 类型和Nested 类型查询

[英]Combining Join type with Nested type and querying in Elasticsearch 6.x

所有,我都在玩带有 NEST 的 ElasticSearch 6.x,为了简单起见,我根据此处提供的 NEST 6.x 文档使用以下 POCO 设置创建了映射https://www.elastic.co/guide/en/elasticsearch /client/net-api/current/parent-child-relationships.html 我的数据模型是一个简单的

  • 顾客

  • 命令

  • 包裹

  • 订单项

    这是 C# POCO 设置

    [ElasticsearchType(Name = "customer")] public class Customer { [PropertyName("customerId")] public int CustomerId { get; set; } [PropertyName("firstName")] [Text] public string FirstName { get; set; } [PropertyName("lastName")] [Text] public string LastName { get; set; } [PropertyName("email")] [Keyword] public string Email { get; set; } [PropertyName("customer_join_field")] public JoinField CustomerJoinField { get; set; } } [ElasticsearchType(Name = "order")] public class Order : Customer { [PropertyName("orderId")] public int OrderId { get; set; } [PropertyName("orderAmount")] public decimal Amount { get; set; } [Nested] [PropertyName("packages")] public List<Package> Packages { get; set; } [Nested] [PropertyName("orderItems")] public List<OrderItem> OrderItems { get; set; } } public class Package { public int PackageId { get; set; } public int Qty { get; set; } public int OrderId { get; set; } public string Weight { get; set; } } public class OrderItem { public int OrderItemId { get; set; } public int Quantity { get; set; } public decimal UnitPrice { get; set; } }

构建 ES 客户端

    public static ElasticClient ESClient
    {
        get
        {

            var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
            var settings = new ConnectionSettings(connectionPool)
                                          .DefaultMappingFor<Customer>(i => i
                                          .IndexName("fa")
                                          .TypeName("customer"))
                                          .DefaultMappingFor<Order>(i => i
                                          .IndexName("fa")
                                          .TypeName("customer"))                                              
                                          .EnableDebugMode()
                                          .PrettyJson()
                                          .RequestTimeout(TimeSpan.FromMinutes(2));

            return new ElasticClient(settings);
        }
    }

配置索引(fa)

public static void ConfigureIndex()
{
    try
    {
        var createIndexResponse = ESClient.CreateIndex("fa", c => c
             .Index<Customer>()
             .Mappings(ms => ms
             .Map<Customer>(m => m
             .RoutingField(r => r.Required())
             .AutoMap<Customer>()
             .AutoMap<Order>()
             .Properties(props => props
                .Join(j => j
                    .Name(p => p.CustomerJoinField)
                    .Relations(r => r
                        .Join<Customer, Order>()
                        )
                    )
                 )
              )
          )
     );

    }

添加客户和订单类型(在同一个客户类型下,因为在 ES 6.x 中一个索引只能有一种类型)

public static void AddCustomerDocument(Customer cust)
    {
        try
        {
            var result = ESClient.Index<Customer>(cust,
                 c => c
                 .Id(cust.CustomerId)//to avaoid random Ids
                 .Routing(cust.CustomerId)
                );

            //var response = ESClient.Index(cust, i => i.Routing(Routing.From(cust)));
        }
        catch (Exception ex)
        {

            throw;
        }
    }   



public static void AddOrderDocument(Order order)
    {
        try
        {


            var result = ESClient.Index<Customer>(order,
                 c => c
                 .Id(order.OrderId)//to avaoid random Ids
                 .Routing(order.CustomerId)
                );

            //var response = ESClient.IndexDocument<Order>(order);
        }
        catch (Exception ex)
        {

            throw;
        }
    }

ES中生成的映射是

{
    "fa": {
        "mappings": {
            "customer": {
                "_routing": {
                    "required": true
                },
                "properties": {
                    "customerId": {
                        "type": "integer"
                    },
                    "customer_join_field": {
                        "type": "join",
                        "eager_global_ordinals": true,
                        "relations": {
                            "customer": "order"
                        }
                    },
                    "email": {
                        "type": "keyword"
                    },
                    "firstName": {
                        "type": "text"
                    },
                    "lastName": {
                        "type": "text"
                    },
                    "orderAmount": {
                        "type": "double"
                    },
                    "orderId": {
                        "type": "integer"
                    },
                    "orderItems": {
                        "type": "nested",
                        "properties": {
                            "orderItemId": {
                                "type": "integer"
                            },
                            "quantity": {
                                "type": "integer"
                            },
                            "unitPrice": {
                                "type": "double"
                            }
                        }
                    },
                    "packages": {
                        "type": "nested",
                        "properties": {
                            "orderId": {
                                "type": "integer"
                            },
                            "packageId": {
                                "type": "integer"
                            },
                            "qty": {
                                "type": "integer"
                            },
                            "weight": {
                                "type": "text",
                                "fields": {
                                    "keyword": {
                                        "type": "keyword",
                                        "ignore_above": 256
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

我正在查询此索引以获取特定客户(CustomerId= 1)下的特定订单项,单价为 12.23。

这是我拥有的查询 DSL

{

    "query":{

        "parent_id":{
            "type":"order",
            "id":"1"
        },
            "nested":{
            "path":"orderItems",
            "score_mode":"avg",
            "query":{
                "bool":{
                    "must":[
                          {"match":{"orderItems.unitPrice" : "12.23"}}
                        ]
                }
            }
        }
    }
}

当我这样做时,我收到以下错误消息

{
    "error": {
        "root_cause": [
            {
                "type": "parsing_exception",
                "reason": "[parent_id] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
                "line": 9,
                "col": 4
            }
        ],
        "type": "parsing_exception",
        "reason": "[parent_id] malformed query, expected [END_OBJECT] but found [FIELD_NAME]",
        "line": 9,
        "col": 4
    },
    "status": 400
}

我的问题是

  1. 是否可以(或推荐)在 ES 6.x 中同时处理父子关系和嵌套类型?

  2. 如果不是,我的选择是否仅限于对模型进行非规范化(有包,OrderItems 是 Customer 的孩子,而不是 Order 并在 Package 和 OrderItems 中添加字段?)或者对 ES 进行多次查询并移动扁平化数据格式的逻辑我要申请方?

这是我创建的示例数据 (localhost:9200/fa/customer/_search)

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 3,
        "max_score": 1,
        "hits": [
            {
                "_index": "fa",
                "_type": "customer",
                "_id": "1",
                "_score": 1,
                "_routing": "1",
                "_source": {
                    "customerId": 1,
                    "firstName": "Rennish",
                    "lastName": "Joseph",
                    "email": "rennish@yahoo.com",
                    "customer_join_field": "customer"
                }
            },
            {
                "_index": "fa",
                "_type": "customer",
                "_id": "100",
                "_score": 1,
                "_routing": "1",
                "_source": {
                    "orderId": 100,
                    "orderAmount": 23.45,
                    "packages": [
                        {
                            "packageId": 1,
                            "qty": 2,
                            "orderId": 1,
                            "weight": "2.3"
                        },
                        {
                            "packageId": 2,
                            "qty": 1,
                            "orderId": 1,
                            "weight": "2.5"
                        }
                    ],
                    "orderItems": [
                        {
                            "orderItemId": 1,
                            "quantity": 2,
                            "unitPrice": 12.23
                        },
                        {
                            "orderItemId": 2,
                            "quantity": 1,
                            "unitPrice": 10.23
                        }
                    ],
                    "customerId": 1,
                    "customer_join_field": {
                        "name": "order",
                        "parent": "1"
                    }
                }
            },
            {
                "_index": "fa",
                "_type": "customer",
                "_id": "101",
                "_score": 1,
                "_routing": "1",
                "_source": {
                    "orderId": 101,
                    "orderAmount": 23.45,
                    "packages": [
                        {
                            "packageId": 1,
                            "qty": 2,
                            "orderId": 1,
                            "weight": "2.3"
                        },
                        {
                            "packageId": 2,
                            "qty": 1,
                            "orderId": 1,
                            "weight": "2.5"
                        }
                    ],
                    "orderItems": [
                        {
                            "orderItemId": 1,
                            "quantity": 2,
                            "unitPrice": 12.23
                        },
                        {
                            "orderItemId": 2,
                            "quantity": 1,
                            "unitPrice": 10.23
                        }
                    ],
                    "customerId": 1,
                    "customer_join_field": {
                        "name": "order",
                        "parent": "1"
                    }
                }
            }
        ]
    }
}

我们最终为这些实体(客户、订单、包裹等)中的每一个创建了单独的索引,并从我们的应用程序中查询所有这些索引并将结果合并到应用程序中。 这是我们一直在与 Elasticsearch 合作的顾问的建议。 我们没有在任何索引映射中做父子关系。 这可能对将来的某人有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM