Space Vatican

Cuando indexas datos, el mundo rara vez es tan simple como cada documento existente de forma aislada. A veces, es mejor desnormalizar todos los datos en los documentos secundarios. Por ejemplo, si estuviera modelando libros, agregar un campo de autor a libros podría ser una opción sensata (incluso si en la base de datos que es su fuente de datos autorizada, los datos se dividen en tablas authors y books separadas). Es simple y puede construir consultas fácilmente sobre ambos atributos del libro y el nombre del autor.

Eso no siempre es práctico: puede haber demasiados datos en el documento padre para duplicarlos en cada documento hijo. Si tuvieras tu aplicación de blog/comentario típica, entonces no querrías repetir todo el contenido de la publicación del blog en cada comentario, ya que esto aumentaría enormemente la cantidad de datos indexados varios. Sin embargo, sin eso, no puede escribir consultas fácilmente para encontrar comentarios en publicaciones que coincidan con ciertos criterios (aparte de hacer un proceso de 2 pasos: primero encontrar publicaciones coincidentes y luego buscar comentarios con un cierto post_id, que a menudo es difícil de manejar o lento (o ambos)).

Otra opción es colocar documentos secundarios dentro del documento principal, por ejemplo, puede tener documentos del formulario

123456789101112
{ "name": "A. N Author", "biography": "A leading wordsmith", "books": }

Un inconveniente aquí es que agregar un hijo requiere reindexar todo el documento. Encontrar autores que han escrito libros con un género determinado es fácil, pero encontrar autores que han publicado un libro de ciencia ficción por penguin es más difícil.

Si nuestro índice contiene

, la consulta más obvia

encuentra a ambos autores ; no puede expresar que sus condiciones en published y genre deban coincidir con el mismo libro.

ElasticSearch proporciona dos cosas que ayudan con esto. El primero es el concepto de documento/consulta anidado. Esto le permite decir que está buscando autores donde al menos un libro satisface ambos criterios.

Primero debe configurar una asignación que diga que el campo libros se anidará:

123456789
curl -XPOST localhost:9200/authors/nested_author/_mapping -d '{ "nested_author":{ "properties":{ "books": { "type": "nested" } } }}'

Si luego insertamos los mismos datos que antes en este nuevo índice, entonces esta consulta

Aquí el filtro nested le permite ejecutar una consulta contra los documentos anidados (es decir, los libros) y filtrar autores por aquellos que tienen al menos un documento anidado que coincida con la consulta. La opción path nos indica a qué parte del documento de autor se aplica esta consulta y, a continuación, la opción query es una consulta que se ejecuta contra estos documentos anidados. A diferencia de la consulta anterior, esto requiere que se encuentre un libro individual que cumpla ambos requisitos, por lo que solo se devuelve Alaistair Reynolds

Padre & hijo

El otro concepto que proporciona elasticsearch es el de una relación padre e hijo entre documentos. El ejemplo anterior se puede volver a trabajar con autores como documentos principales y libros como documentos secundarios.

Esta vez, indice a los autores por separado de sus libros:

Luego configure la asignación para el tipo de libro y diga que su tipo principal es bare_author. Necesitas hacer esto antes de crear cualquier libro.

12345
curl -XPOST localhost:9200/authors/book/_mapping -d '{ "book":{ "_parent": {"type": "bare_author"} }}'

Cuando indexamos libros, debe dar el id de su padre (es decir, suministramos el id de uno de los autores creados previamente)

Elasticsearch proporciona un filtro has_child que hace más o menos lo que se dice en la lata: selecciona documentos principales con al menos un hijo que satisfaga una determinada consulta. Esta consulta solo encuentra Alastair Reynolds:

Solr 4.0 aparentemente tendrá la capacidad de hacer uniones, aunque por lo que puedo decir esto viene con algunas restricciones, en particular, sin uniones si se opera en un entorno distribuido. Al limitarse a las relaciones de tipo padre/hijo, elasticsearch se hace la vida más fácil: un hijo siempre se indexa en el mismo fragmento que su padre, por lo que has_child no tiene que realizar operaciones incómodas de fragmento cruzado.

Crear listas

También puede usar esto para modelar listas específicas de usuarios de elementos globales compartidos, por ejemplo, si desea elementos que un usuario haya calificado. En este caso, los documentos secundarios representarían el hecho de que un usuario específico ha calificado una publicación específica: no son más que user_id, post_id y una clasificación: una tabla de unión en la jerga de la base de datos relacional.

El uso de relaciones padre/hijo y has_child le permite encontrar fácilmente todas las publicaciones favoritas de un usuario, al tiempo que permite a los usuarios buscar en sus favoritos según el contenido de la publicación, la fecha o cualquier otro de los atributos de una publicación o cualquiera de las propiedades del elemento secundario. Agregar un artículo a la lista de artículos clasificados es barato, solo requiere indexar un artículo muy pequeño rating.

Con estos documentos

Esta consulta

encuentra solo «bolivia clasificado 4» ya que es el único post que menciona a bolivia que ha sido calificado por encima de 3 por el usuario que nos interesa. La consulta de nivel superior en el título se aplica a las publicaciones, donde la consulta dentro del filtro has_child describe las condiciones que los hijos deben coincidir (en este caso, deben pertenecer a un usuario específico y tener al menos una cierta calificación).

Ordenar

Lo que has_child no le permite hacer es ordenar en función de los atributos de los hijos o devolver atributos del hijo. Si deseas ordenar las publicaciones calificadas de un usuario en función de cuándo fueron calificadas o disminuyendo la calificación, puedes buscar directamente en las publicaciones/calificaciones, pero es posible que también desees aplicar algunos criterios de búsqueda a las publicaciones. Por ejemplo, es posible que desee encontrar solo publicaciones calificadas sobre un tema determinado (aún ordenando según la calificación que dio el usuario). Con has_child, no tienes suerte. Los documentos anidados tampoco ayudan.

A partir de 0.19.10 puede utilizar el filtro has_parent. Esto funciona casi exactamente igual que tiene hijos, pero le permite especificar una consulta contra los elementos principales en su lugar. Esta consulta devuelve las calificaciones del usuario 1234, en publicaciones cuyo título coincide con «bolivia», en orden decreciente de puntuación

Esto devuelve los objetos de calificación; luego tendría que buscar las publicaciones correspondientes con una consulta separada.

Fingirlo

Si estás atascado en una versión anterior de elasticsearch, puedes realizar la mayor parte del camino con top_children. Como dice la documentación top_children primero consulta los documentos secundarios y luego los agrega en documentos principales. En nuestro ejemplo, esto significa que elasticsearch encontrará primero los documentos de calificación que coincidan con nuestra consulta. Luego, emparejará cada calificación con su publicación principal, agregando publicaciones duplicadas donde existan.

Lo difícil con los hijos superiores es que elasticsearch no sabe de antemano cuántos documentos perderá cuando se produzca la agregación. En este caso en particular, es fácil porque dos calificaciones distintas por el mismo usuario siempre corresponden a dos publicaciones distintas, por lo que no necesitamos molestarnos con los ajustes factor y incremental_factor porque la fase de agregación nunca hace nada. Del mismo modo, el modo de puntuación tampoco importa. Si necesita proporcionar un recuento preciso del número total de resultados, solo necesita establecer factor lo suficientemente grande como para que el primer barrido que elasticsearch haga de los documentos secundarios los encuentre todos. Si sabes que el usuario tiene 500 artículos clasificados en su lista y estás pidiendo los primeros 10 artículos, entonces un factor de 50 debería hacer el truco. El factor solo necesita ser un límite superior: no necesita saber exactamente cuántos elementos tiene el usuario en su lista (lo que podría ser incómodo de resolver sin una consulta de búsqueda elástica separada si el usuario está buscando un subconjunto específico de sus calificaciones).

Lo que obtienes después de todo esto es una lista de documentos principales (publicaciones) ordenados por la puntuación de consulta de los documentos secundarios (calificaciones). Para lograr el objetivo original de ordenar las publicaciones en función de los atributos de los documentos secundarios, solo necesitamos asegurarnos de que esta puntuación de consulta tenga el valor correcto. Por ejemplo, haga que top_children encapsule una consulta custom_score para que pueda controlar cuál es la puntuación de cada hijo.

Con los mismos documentos en el índice, esta consulta devuelve las publicaciones que el usuario 1234 ha calificado, ordenadas por su calificación:

Estamos ejecutando una consulta top_children, por lo que lo primero que tenemos que hacer es decir cuál es el tipo de hijos que estamos considerando (clasificación). Luego proporcionamos la consulta que encuentra a esos niños. Esta es una consulta custom_score, envolviendo una consulta filtered. La consulta filtered garantiza que solo encontremos las calificaciones dadas por el usuario en el que estamos interesados, y luego el elemento script hace que la puntuación del documento de calificación se califique en sí, de modo que obtenemos nuestras publicaciones ordenadas por calificación. Lo raro de las barras invertidas es solo porque estoy tratando de incluir una comilla simple literal en una cadena amigable con el shell delimitada por comillas simples: el json real que estamos enviando tiene solo "script": "doc.value".

Ruby fun

Desafortunadamente, la biblioteca de neumáticos en realidad no admite ninguna de estas cosas divertidas en este momento, hay una moratoria en este tipo de característica que se agrega porque en este momento cada pequeño tipo de consulta y opción termina siendo métodos separados dispersos por todo el neumático, lo que comprensiblemente no le gusta al mantenedor. Sin embargo, puedes hackearlo.

Tire no le permite establecer el ID de padre de un documento al indexar. Esto es fácil de añadir y solo se está retrasando por la moratoria mencionada anteriormente. Mi tenedor añade esta habilidad. Con eso, terminas con

La siguiente parte de infelicidad es que la creación del índice automático de tire supone un tipo por índice, pero para que exista una relación padre/hijo, ambos tipos deben estar en el mismo índice. Terminé haciendo algo como esto para crear mis índices.

que no es tan hermoso, pero hace el trabajo.

Por último, necesita hacer la consulta. En la ausencia de top_children ser parte de la llanta de la api puede fudge de él

Este poco de desagrado se acumula la consulta como un hash y luego se mete en los neumáticos, mientras que mirando a otro lado. Obviamente, puedes estructurarlo de tal manera que sea fácil agregar otras condiciones (ya sea en la Publicación o en la Calificación) a la búsqueda. También puede crear el json manualmente y usar Post.search :payload => my_json (hay un error con la opción de carga útil que choca con la extensión del registrador de tire-contrib)

Deja una respuesta

Tu dirección de correo electrónico no será publicada.