Объединение типа соединения с вложенным типом и запросов в Elasticsearch 6.x - PullRequest
0 голосов
/ 04 июня 2018

Все, я играю с ElasticSearch 6.x с NEST, и для простоты я создал сопоставления со следующими настройками POCO на основе документации NEST 6.x, предоставленной здесь https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/parent-child-relationships.html. Моя модель данных простаодин с

  • Заказчик

  • Заказ

  • Пакет

  • OrderItem

    Вот настройки 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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Я запрашиваю этот индекс, чтобы получить конкретный OrderItem под конкретным клиентом (CustomerId = 1) с ценой за единицу 12.23.

Это Query 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. Если нет, мои параметры ограничены денормализациеймодели (имеют package, а OrderItems будут дочерними для Customer, а не поля Order и add в 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"
                    }
                }
            }
        ]
    }
}
...