sorting - specify - query field elasticsearch
ElasticSearch agregación multinivel padre-hijo (2)
Tengo una estructura padre / hijo en 3 niveles.
Digamos:
Empresa -> Empleado -> Disponibilidad
Como Disponibilidad (y también Empleado) se actualiza con frecuencia aquí, elijo usar la estructura padre / hijo contra anidada. Y la función de búsqueda funciona bien (todos los documentos en fragmentos correctos).
Ahora quiero ordenar esos resultados. Ordenarlos por metadatos de la compañía (primer nivel) es fácil. Pero necesito ordenar también por 3er nivel (disponibilidad).
Quiero una lista de empresas ordenadas por:
- Distancia desde la ubicación dada ASC
- Calificación DESC
- Disponibilidad más pronto ASC
Por ejemplo:
La Compañía A está a 5 millas de distancia, tiene una calificación de 4 y pronto uno de sus empleados está disponible en 20 horas La Compañía B también está a 5 millas de distancia, también tiene una calificación de 4 pero pronto uno de sus empleados está disponible en 5 horas.
Por lo tanto, el resultado de clasificación debe ser B, A.
Me gustaría agregar un peso especial a cada uno de estos datos, así que comencé a escribir agregaciones que luego podría usar en mi script custom_score.
Resumen completo para crear índices, importar datos y buscar
Ahora, he logrado escribir una consulta que realmente devuelve el resultado, pero el depósito de agregación de disponibilidad está vacío.
Sin embargo, también estoy obteniendo resultados demasiado estructurados, me gustaría aplanarlos.
Actualmente regreso:
ID de empresa -> ID de empleado -> primera disponibilidad
Me gustaría tener agregaciones como:
IDS de la empresa -> primera disponibilidad
De esta manera, puedo hacer mi script
custom_score
para calcular la puntuación y ordenarlos correctamente.
Pregunta más simplificada:
¿Cómo se puede clasificar / agregar por varios niveles (grand) hijos y posiblemente aplanar el resultado.
Debe consultar la estructura de datos de R-Tree https://en.wikipedia.org/wiki/R-tree .
No necesita agregaciones para hacer esto:
Estos son los criterios de clasificación:
- Distancia ASC (empresa.ubicación)
- Calificación DESC (company.rating_value)
- Pronto disponibilidad futura ASC (company.employee.availability.start)
Si ignora el n. ° 3, puede ejecutar una consulta de empresa relativamente simple como esta:
GET /companies/company/_search
{
"query": { "match_all" : {} },
"sort": {
"_script": {
"params": {
"lat": 51.5186,
"lon": -0.1347
},
"lang": "groovy",
"type": "number",
"order": "asc",
"script": "doc[''location''].distanceInMiles(lat,lon)"
},
"rating_value": { "order": "desc" }
}
}
El n. ° 3 es complicado porque necesita alcanzar y encontrar la disponibilidad ( empresa> empleado> disponibilidad ) para cada compañía más cercana al momento de la solicitud y usar esa duración como un tercer criterio de clasificación.
Vamos a utilizar una consulta
function_score
en el nivel de nieto para tomar la diferencia horaria entre el tiempo de solicitud y cada disponibilidad en el hit
_score
.
(Luego usaremos el
_score
como el tercer criterio de clasificación).
Para llegar a los nietos necesitamos usar una consulta
has_child
dentro de una consulta
has_child
.
Para cada empresa, queremos el Empleado más pronto disponible (y, por supuesto, su Disponibilidad más cercana).
Elasticsearch 2.0 nos dará un
"score_mode": "min"
para casos como este, pero por ahora, ya que estamos limitados a
"score_mode": "max"
haremos que el nieto
_score
sea el
recíproco
de la diferencia horaria .
"function_score": {
"filter": {
"range": {
"start": {
"gt": "2014-12-22T10:34:18+01:00"
}
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"params": {
"requested": "2014-12-22T10:34:18+01:00",
"millisPerHour": 3600000
},
"script": "1 / ((doc[''availability.start''].value - new DateTime(requested).getMillis()) / millisPerHour)"
}
}
]
}
Por lo tanto, ahora la
_score
para cada nieto (
Disponibilidad
) será
1 / number-of-hours-until-available
(para que podamos utilizar el tiempo
recíproco máximo
hasta que esté disponible por Empleado, y el Empleado
recíproco máximo
disponible por empresa) )
En conjunto, seguimos consultando a la
empresa,
pero usamos la disponibilidad
empresa> empleado>
para generar el
_score
para usar como criterio de clasificación n.
° 3
:
GET /companies/company/_search
{
"query": {
"has_child" : {
"type" : "employee",
"score_mode" : "max",
"query": {
"has_child" : {
"type" : "availability",
"score_mode" : "max",
"query": {
"function_score": {
"filter": {
"range": {
"start": {
"gt": "2014-12-22T10:34:18+01:00"
}
}
},
"functions": [
{
"script_score": {
"lang": "groovy",
"params": {
"requested": "2014-12-22T10:34:18+01:00",
"millisPerHour": 3600000
},
"script": "1/((doc[''availability.start''].value - new DateTime(requested).getMillis()) / millisPerHour)"
}
}
]
}
}
}
}
}
},
"sort": {
"_script": {
"params": {
"lat": 51.5186,
"lon": -0.1347
},
"lang": "groovy",
"type": "number",
"order": "asc",
"script": "doc[''location''].distanceInMiles(lat,lon)"
},
"rating_value": { "order": "desc" },
"_score": { "order": "asc" }
}
}