Изменение родителей в индексе

Привет !

я хочу сделать индекс в котором будет два типа Group и Person. Group - Parent, Person - child. в каждую группу может входить несколько людей. проблема в томь что состав групп может менияться, так что мне нужно так же менять родителей у детей. возможно ли менять каким либо образом routing и ка это делать?

Спасибо

Надо удалить старую запись используя старый раутинг, и потом добавить измененную запись используя новый.

спасибо! т.е. если у меня 20 000 000 человек, то мне нужно будет всех их переписывать....
А если попробовать сделать группу ребенком и человека - родителем? возможно ли будет отсортировать людей по дате рождения, и выбрать тех, кто находится в первых 10 разных группах ?

Тут либо переписывать родителя или всех детей. В elasticsearch любое изменение записи это ее удаление и запись снова. Просто если раутинг не меняется то elasticsearch это делает автоматически.

У записи не может быть больше одного родителя.

я думаю дулировать детей. и поэтому будет дублироваться информация. вот и возник вопрос о distinct query c aggregation

Тогда я не понимаю, что вы пытаетесь тут сделать.

я сдделаю структуру Person - parent, Group-child.
таким образом для каждого родителся будет только один ребенок.
мне нужно отсоритровать людей и выбрать только из первых 10 разных групп
|person|group|
|1|1|
|2|2|
|3|2|
|4|3|
|5|4|
|6|5|
|7|6|
|8|7|
|9|7|
|10|8|
|11|9|
|12|10|
|13|11|

т.е. я должна полечть только людей с 1 по 12

А зачем тогда создавать 2 записи?

потому что группы будут меняться каждый день

А если человек 9 в 1-й группе то как список должен быть отсортирован? Тот же вопрос про человека под номером 14.

у нас уже был вечер.... нужно напечатать группы. для примера выше это должно быть 1 2 10 4 5 6 7 8 9 11
т.е. отсортировать родителей и потом выбрать первых 10 distinct детей

{
  "from": 0,
  "query": {
    "has_parent": {
      "parent_type": "persontype",
      "score": true,
      "query": {
        "bool": {
          "must": [
            {
              "bool": {
                "must": [
                  {
                    "query_string": {
                      "fields": [
                        "name"
                      ],
                      "lenient": true,
                      "query": "paulina cruz"
                    }
                  }
                ]
              }
            }
          ]
        }
      },
      "inner_hits": {
        "highlight": {
          "fields": {
            "name": {}
          }
        }
      }
    }
  },
  "aggs": {
    "unique_title": {
      "terms": {
        "field": "documentId",
        "order": {
          "max_score": "desc"
        }
      },
      "aggs": {
        "max_score": {
          "max": {
            "script": "_score"
          }
        }
      }
    }
  },
  "_source": {
    "excludes": [
      "*"
    ]
  }
}

вот какое примерное query у меня получилось. выдает более менее корректные результаты.
Следующий вопрос - я изначально использовала

"query": {
"bool": {
  "must": [
    {
      "bool": {
        "must": [
          {
            "query_string": {
              "fields": [
                "name"
              ],
              "lenient": true,
              "query": "*paulina cruz*"
            }
          }
        ]
      }
    }
  ]
}
  }

и если я используб точно такое же query в HasParent я получаю другие результаты.
фильтр только по родителям дает мне 11 результатов, но когда я фильтрую родителей через детей я получаю 8 результатов в другом порядке.

Вопрос - почему одно и тоже query дает разные результаты и как этого избежать?

Так это два очень разных запроса, один ищет по суффиксу и префиксу а второй по обычному совпадению.

я использовала именно запрос query string в двух случаях. и он мне выдает разные результаты

"query": {
"bool": {
  "must": [
    {
      "bool": {
        "must": [
          {
            "query_string": {
              "fields": [
                "name"
              ],
              "lenient": true,
              "query": "*paulina cruz*"
            }
          }
        ]
      }
    }
  ]
}
  }

при запросе конкретно к PersonType 11 записей

15 Paulina Name Cruz
17 Name Paulina Cruz
19 Cruz
22 Cruz Name NAme
21 NAme Cruz
20 Name Paulina
13 Paulina Crruz
16 Paulina-Name Cruz
18 Paulina
23 Paulina Name Name

при запросе hasParent 8 записей

17 Name Paulina Cruz
19 Cruz
22 Cruz Name NAme
21 NAme Cruz
20 Name Paulina
16 Paulina-Name Cruz
18 Paulina
23 Paulina Name Name

score для первых записей 2 для остальных всегда 1. может у вас есть предложения как сделыть поиск более релевантным ?

извините ! я поняла почему у меня выдаются неправильные результаты....

новый вопрос :grinning:

возможно ли сортировать детей по нескольким полям у родителей ? т.е я хочу сортирвать сначала по score и потом по дате рождения.

{
  "from": 0,
  "query": {
"has_parent": {
  "parent_type": "persontype",
  "score": true,
  "query": {
    "function_score": {
      "query": {
        "common": {
          "name": {
            "query": "paulina cruz",
            "cutoff_frequency": 0.001,
            "low_freq_operator": "and"
          }
        }
      },
      "script_score": {
        "script": "_score * doc['dateOfBirth'].value"
      }
    }
  },
  "inner_hits": {
    "highlight": {
      "fields": {
        "name": {},
        "dateOfBirth": {}
      }
    }
  }
}
  },
  "aggs": {
"unique_title": {
  "terms": {
    "field": "documentId",
    
    "order": {
      "avg_score": "desc"
    },
    "size": 5
  },
  "aggs": {
    "avg_score": {
      "max": {
        "script": "_score"
      }
    },
    "bucket_count": {
      "cardinality": {
        "field": "documentId"
      }
    }
  }
},
"distinct_terms": {
  "cardinality": {
    "field": "documentId"
  }
}
  },
  "_source": {
"excludes": [
  "*"
]
  }
}

если можно использовать только script_score, то по двум полям сортировать не получится ?

второй вопрос - как можно сделать pagination с агрегациями ?

  "aggs": {
    "unique_title": {
      "terms": {
        "field": "documentId",
        "include": {
          "partition": 1,
          "num_partitions": 3
        },
        "order": {
          "avg_score": "desc"
        },
        "size": 5
      },
      "aggs": {
        "avg_score": {
          "max": {
            "script": "_score"
          }
        },
        "bucket_count": {
          "cardinality": {
            "field": "documentId"
          }
        }
      }
    },
    "distinct_terms": {
      "cardinality": {
        "field": "documentId"
      }
    }
  },

я пробовала с includes, но как я могу рассчитать num_partition ?

Pagination работает только с composite aggs.

т.е. либо мы обновляем версию, либо берем 1000 buckets и используем кэш....

я столкнулась с проблемой: когда score одинаковый для всех записей, buckets беруться в рандомном порядке. как я могу их выбрать по их Id в том порядке в котором они появляются в query ?

Можно попробовать как-нибудь объединить ключи в script.

Спасибо большое за все подсказки !
в итоге у мения получилось следуьщее query

{
  "aggs": {
    "groupId": {
      "aggs": {
        "current_score": {
          "max": {
            "script": {
              "inline": "_score"
            }
          }
        }
      },
      "terms": {
        "field": "documentId",
        "order": [
          {
            "current_score": "desc"
          }
        ],
        "size": 10
      }
    },
    "totalDistinct": {
      "cardinality": {
        "field": "documentId"
      }
    }
  },
  "from": 0,
  "query": {
    "has_parent": {
      "query": {
        "function_score": {
          "functions": [
            {
              "script_score": {
                "script": {
                  "inline": "doc['dateOfBirth'].value",
                  "lang": "groovy"
                }
              }
            }
          ],
          "query": {
            "bool": {
              "must": [
                {
                  "bool": {
                    "minimum_should_match": 1,
                    "should": [
                      {
                        "query_string": {
                          "boost": 2,
                          "fields": [
                            "name"
                          ],
                          "lenient": true,
                          "query": "*Paulina Cruz*"
                        }
                      },
                      {
                        "query_string": {
                          "fields": [
                            "name.keyword"
                          ],
                          "lenient": true,
                          "query": "*Paulina Cruz*"
                        }
                      }
                    ]
                  }
                },
                {
                  "bool": {
                    "must": [
                      {
                        "exists": {
                          "field": "id"
                        }
                      }
                    ]
                  }
                }
              ]
            }
          }
        }
      },
      "score": true,
      "type": "persontype"
    }
  },
  "_source": {
    "excludes": [
      "*"
    ]
  }
}

query для нахождения общего количества элементов

{
  "aggs": {
    "totalDistinct": {
      "cardinality": {
        "field": "documentId"
      }
    }
  },
  "query": {
    "has_parent": {
      "query": {
        "bool": {
          "must": [
            {
              "exists": {
                "field": "id"
              }
            }
          ]
        }
      },
      "type": "persontype"
    }
  },
  "_source": {
    "excludes": [
      "*"
    ]
  }
}

C# версия

body
                    .Index(_type.GetIndexName())
                    .Source(src => src.ExcludeAll())
                    .Query(q => q.HasParent<PersonType>(
                               p => p
                                       .Score(true)
                                       .Query(qqq => qqq
                                                  .FunctionScore(fs => fs
                                                                       .Query(qq => qq.Bool(b => b
                                                                                                 .Filter(permissionContainer, personFilter)
                                                                                                 .Must(queryContainers.ToArray())))
                                                                       .Functions(fct => fct
                                                                                      .ScriptScore(ss => ss
                                                                                                       .Script(cs => cs
                                                                                                                     .Inline(_descriptors.GetOrderScript(parameters.Sort))
                                                                                                                     .Lang(ScriptLang.Groovy))
                                         ))))));

                body.Aggregations(
                    aggs => aggs
                            .Terms("groupId", gr => gr
                                    .Field(f => f.DocumentId)
                                    .Order(
                                        new TermsOrder
                                        {
                                            Key = "current_score",
                                            Order = parameters.Sort.Order == Order.ASC
                                                        ? appliedSort ? SortOrder.Ascending : SortOrder.Descending
                                                        : SortOrder.Descending
                                        })
                                    .Size(parameters.Start + parameters.Length)
                                    .Aggregations(
                                           aggss => aggss
                                               .Max("current_score", tt => tt.Script("_score"))))
                            .Cardinality("totalDistinct", c => c.Field(f => f.DocumentId))
                );

                body.From(0);

                return body;

т.к. используем вегсию 5,5 многие aggregations для нас недоступны. поэтому для pagination я брала все элементы (parameters.Start + parameters.Length) и потом из них выбирала последние.

var response = Query(parameters, user, applyPermissions, flags);
            return new SearchResult<long>
            {
                Items = (response.Aggregations["groupId"] as BucketAggregate)?
                    .Items
                        .Cast<KeyedBucket<object>>()
                        .Select(bucket => long.Parse(bucket.KeyAsString ?? bucket.Key.ToString()))
                        .Skip(parameters.Start)
                        .ToList(),
                ItemsCount = (long?)((ValueAggregate)response.Aggregations["totalDistinct"])?.Value ?? 0,
                TotalCount = CountByType(user, applyPermissions, flags)
            };

Надеюсь мой опыт кому-нибудь поможет !
Еще раз, большое спасибо