ElasticSearch se une: Has_Child, consulta Has_parent

ElasticSearch se une: Has_Child, consulta Has_parent

  • Orquestación
5 min de lectura Actualizado Dec 6, 2018

Puntos clave: ElasticSearch utiliza relaciones padre-hijo para gestionar asociaciones de documentos, de forma similar a las uniones relacionales de bases de datos. La guía explica cómo Crea mapeos y consultas para estas relaciones, enfatizando la arquitectura centrada en la velocidad de ElasticSearch que limita las uniones tradicionales. Ejemplos clave incluyen la creación de datos para universidades y estudiantes, demostrar la configuración de documentos padre e hijo, y consultar registros hijos por ID padre.

  • ElasticSearch no está una base de datos relacional y evita las uniones tradicionales.
  • Las relaciones padre-hijo son establecen mediante mapeos y consultas específicas.

Una vez más abordamos la complejidad y a veces contradictoria la documentación de ElasticSearch e intentamos Haz más fácil de entender. Aquí analizamos cómo establecer las relaciones padre-hijo entre documentos.

Los conceptos Padre, Hijo y Unir

En una base de datos relacional, una relación padre-hijo se está llamada unión. Un matemático llamaría a eso la intersección de dos conjuntos. Por ejemplo, podemos encontrar la intersección de un conjunto de números impares y números primos, creando un conjunto de números impares que no son primos.

Una persona de base de datos expresaría eso en una relación padre-hijo. Para ello están necesarios son algún elemento común.

Para ilustrar, supongamos que tenemos estos dos conjuntos, algunos números impares y algunos números primos. Entonces Haz la intersección de los dos conjuntos, es decir, el conjunto de elementos que son en ambos. Una unión a bases de datos está igual.

padre (algunos números impares)
{9,21}
Hijos (algún número primo)
{7,11, 21}
Intersección (números impares ∩ números primos)
{21}

En este caso no importa qué conjunto elegimos como padre o hijo, ya que son solo números.

Lo ilustraremos en ElasticSearch usando universidades y estudiantes. Crea un conjunto de universidades y estudiantes y luego asignaremos a cada uno.

Así que tendremos algo como:

Madre (universidades)
{Harvard, Clemson}
Niños (estudiantes)
{{"estudiante:" Walker",
"universidad": "Clemson},
{estudiante: Stephen",
"universidad": "Harvard"}}
intersección 
(estudiantes que van a Clemson)
{"estudiante:" Walker",
"universidad": "Clemson}

El hijo apunta al padre porque el nombre de la universidad está en el registro de Chile. Ese es el elemento común. En términos de ElasticSearch te indica esto en el mapeo del índice así:

    "universities_students" : {
          "type" : "join",
            "eager_global_ordinals" : true,
            "relations" : {
              "universities" : "students"
          }
     }

Esto crea un nuevo campo con el nombre universities_students que están de tipo se unen. El padre están universidades y el niño están estudiantes.

Cuando te escribo un registro de estudiante (hijo) te lo apunte a su padre usando la _id, es decir, 'padre': 'e2cfb3b015d4be50a466aa593ab4d9f490982ede' del documento padre, e indica que están un documento de tipo estudiantes:

    'universities_students': {
'name': 'students',
 'parent': 'e2cfb3b015d4be50a466aa593ab4d9f490982ede'
}

Y cuando te escribo un registro universitario (padre) te indicar que están un documento de tipo universidade. te no poner _id porque no sería lógico. La consulta determina esa relación.

    'universities_students': {
'name': 'universities'
}

ElasticSearch no está una base de datos

ElasticSearch señala que no están una base de datos relacional. Por eso no permite te hacer uniones tradicionales porque esas irían demasiado lentas, y ES están todo sobre la velocidad. Por eso requieren que ambos tipos de documentos estén en el mismo shard en el mismo índice. Eso los pone cerca en el mismo disco duro, reduciendo así el tiempo de búsqueda. También señalan que esta consulta irá más lenta a medida que te añadir más documentos incluso con esa regla.

Primer tipo de mapeo Crea

Ahora, ilustramos esto con un ejemplo. Primero, Crea un tipo de mapeo. Ten en cuenta que este tipo de mapeo podrá contener tanto universidades como estudiantes. Esto están porque esta lista de campos está el superconjunto de todos los campos comunes a ambos. Es están, los estudiantes tienen clases y calificaciones, pero las universidades no. De manera similar, las escuelas tienen un correo Administrativo, nombre del centro, etc.

Fíjate que al final listamos el campo universities_students que están de unión de tipos. Esto expresa la relación entre documentos.

(Solo pondremos el nombre de la escuela en el registro de la universidad. te puede ignorar todos esos otros campos, como el número de teléfono. Los usamos en este ejemplo anterior sobre cómo hacer consultas anidadas, que están un tema relacionado, aunque diferente.)

    curl -XPUT --header 'Content-Type: application/json' http://parisx:9200/universities -d '{
"settings" : {
        "index" : {
            "number_of_shards" : 1, 
            "number_of_replicas" : 1 
        }
    },    "mappings" : {
      "doc" : {
        "properties" : {
          "Address" : { "type" : "text"},
          "AdminEmail" : { "type" : "text"},
          "AdminName" : { "type" : "text" },
          "AdminPhone" : { "type" : "text" },
          "DapipId" : { "type" : "text" },
          "Fax" : { "type" : "text" },
          "GeneralPhone" : { "type" : "text" },
          "LocationName" : { "type" : "text" },
          "LocationType" : { "type" : "text" },
          "OpeId" : { "type" : "text" },
          "ParentDapipId" : { "type" : "text" },
          "ParentName" :  { "type" : "text" },
          "UpdateDate" : { "type" : "text" },
          "classes" : {
                "type" : "nested",
                "properties" : {
                   "name" : { "type" : "text"},
                   "grades" : { "type" : "integer" }
              }
            },
        "firstName" : { "type" : "text" },
        "lastName" : { "type" : "text" },
        "school" : { "type" : "text" },
          "universities_students" : {
          "type" : "join",
            "eager_global_ordinals" : true,
            "relations" : {
              "universities" : "students"
          }
          }
        }
        }
}
}'

Crea datos

Descarga y ejecuta este código. Para Haz las cosas sencillas, solo Crea un colegio y un estudiante. Si te quieres experimentar con esto y Crea muchos más datos, simplemente cambia el rango(1,2) a algo como rango(1.400).

te podría Crea datos usando curl, como en los ejemplos de ES en su documentación. Pero es mucho más fácil utiliza Python, ya que es más fácil trabajar con diccionarios de Python que con objetos JSON, especialmente cuando los documentos ES son largos y tienen muchos objetos dentro de los objetos,

Mira los registros universitarios y de estudiantes que aparecen a continuación. Ten en cuenta que al ejecutarlo te generará datos diferentes ya que selecciona escuelas al azar. te necesitas anotar el _id del registro universitario para que te puedas introducirlo en la consulta de abajo que encuentra registros de hijos.

padre (universidad)

    {'school': 'University of South Carolina - Columbia', 'universities_students': {'name': 'universities'}}
{'_version': 1, '_type': 'doc', '_id': 'e2cfb3b015d4be50a466aa593ab4d9f490982ede', '_primary_term': 1, 'result': 'created', '_index': 'universities', '_seq_no': 0, '_shards': {'failed': 0, 'total': 2, 'successful': 2}}

Niño (alumnos)

    {'school': 'University of North Carolina at Chapel Hill', 'universities_students': {'name': 'students', 'parent': 'e2cfb3b015d4be50a466aa593ab4d9f490982ede'}, 'lastName': 'Mann', 'classes': [{'name': 'French', 'grades': 6}, {'name': 'French', 'grades': 3}, {'name': 'French', 'grades': 2}, {'name': 'math', 'grades': 4}], 'firstName': 'Walker'}

Aquí está el código completo. Debajo explicamos aquellas partes que no son evidentes por sí mismas. Simplemente elige una de tres escuelas basándose en un número aleatorio. Selecciona nombres y clases usando este mismo método. Luego añade el registro universitario y estudiantil como explicamos arriba.

El enfoque básico están Crea un diccionario {} y luego añadirle campos. Podemos añadir diccionarios a diccionarios para Crea objetos JSON anidados. Así que es más sencillo que trabajar con campos largos de cadenas JSON.

    import requests
import random
import hashlib
import json

url="http://parisx:9200/universities/doc/" 

def assignClasses():
    classes=[]
    for x in range(random.randrange(1,6)):
      classes.append(genclass())
    return classes 
      
schools = ("Arizona State University", "University of South Carolina - Columbia", "University of North Carolina at Chapel Hill") 
firstNames = ("Walker", "Stephen", "Julie", "George")
lastNames = ("Rowe", "Shakespeare", "Mann", "Sarte")
courses= ("math", "physics", "French", "logic")

def genclass():
    classes={}
    classes["name"]=courses[random.randrange(0,3)]
    classes["grades"] = random.randrange(1,7)
    return classes

def genParent(id):
    child={}
    child['name'] = 'students'
    child['parent'] = id
    return child

def genSchool():
    school={}
    school["universities_students"] = {'name': 'universities'}
    school["school"]=schools[random.randrange(0,3)]
    m = hashlib.sha1()
    m.update(bytes(json.dumps(school), 'utf-8'))
    id = m.hexdigest()
    print(school)
    response = requests.post(url + id, json=school)
    print (response.json())
    return id

def genStudent():
    id = genSchool()
    students={}
    students["universities_students"] = genParent(id)
    students["school"]=schools[random.randrange(0,3)]
    students["firstName"] = firstNames[random.randrange(0,3)]
    students["lastName"] = lastNames[random.randrange(0,3)]
    students["classes"] = assignClasses()
    m = hashlib.sha1()
    m.update(bytes(json.dumps(students), 'utf-8'))
    sid = m.hexdigest()

    print(students)
    response = requests.post(url + sid + "?routing=1&refresh", json=students)
    print (response.json())

for r in range(1,2):
    genStudent()
url="http://parisx:9200
/universidades/doc/"
El índice/tipo sigue siendo una de las partes más confusas de ElasticSearch. Dicen que han eliminado el campo de tipo de documento, pero cuando te escribo datos te son piden que los utiliza en el índice/tipo. Es una contradicción. En este caso, están documentación en universidades/documentos.
m = hashlib.sha1()
m.update(bytes(json.
dumps
(school),'utf-8'))
id = m.hexdigest()
Cada documento de ElasticSearch debe tener un ID único. Si te escribes el mismo ID de documento dos veces, uno borrará al otro. El enfoque común están calcular un resumen SHA1 sobre todo el documento JSON. Por supuesto, dos documentos podrían tener el mismo ID. Tú también podrías utilizar algo como uuid. UUID.
Respuesta = requests.post
(URL + SID
+ "?Enrutamiento=1&Refresh",
json=Estudiantes)
Cuando añadimos el documento hijo, son estamos obligados a decirle qué fragmento utilizar, ya que debe estar en el mismo fragmento y en el documento padre. (Un fragmento es una división de un índice. Está diseñado para distribuir datos entre nodos en un clúster. Esto no está un límite. Aún podemos tener más de un fragmento. Solo tendríamos que poner el enrutamiento también en el padre y utiliza el mismo número de fragmentos mientras rotamos por una lista de esos.) Put dijo a ES cuántos fragmentos Crea cuando creamos el mapa de índice:
"index" : { "number_of_shards" : 1,  "number_of_replicas" : 1  }

Encuentra niños

Ahora tenemos que Crea algunos datos. Así podemos hacer algunas consultas.

El primero encuentra registros de niños dados a un padre. La palabra clave aquí están parent_id. El tipo de objeto que son buscamos están "tipo": "estudiantes". Y le decimos qué escuela buscar poniendo el _id de la escuela en "id": "e2cfb3b015d4be50a466aa593ab4d9f490982ede".

    curl -XGET --header 'Content-Type: application/json' http://parisx:9200/universities/_search?pretty -d '{
  "query": {
    "parent_id": {
      "type": "students",
      "id": "e2cfb3b015d4be50a466aa593ab4d9f490982ede"
    }
  }
}'

Esta consulta lista a este estudiante (recuerda que solo añadimos a un estudiante):

    {
        "_index" : "universities",
        "_type" : "doc",
        "_id" : "185fa8736085fd07ce6f5fb8f1c66fce64fa42e3",
        "_score" : 0.18232156,
        "_routing" : "1",
        "_source" : {
          "classes" : [
            {
              "name" : "French",
              "grades" : 1
            }
          ],
          "school" : "University of South Carolina - Columbia",
          "lastName" : "Mann",
          "universities_students" : {
            "name" : "students",
            "parent" : "e2cfb3b015d4be50a466aa593ab4d9f490982ede"
          },
          "firstName" : "Walker"
        }
      }

Encuentra padres

No está ningún campo en el padre que apunte a los hijos, así que no podemos simplemente poner el ID de los hijos en la consulta. Eso no tendría sentido, porque si conociéramos los IDs de los hijos, ¿para qué referirnos al padre en absoluto? En su lugar, podemos listar todos los documentos de los padres que tengan un hijo.

Utilizamos el parámetro de consulta exists ya que sons obligados a poner algo en el parámetro de consulta.

    curl -XGET --header 'Content-Type: application/json' http://parisx:9200/universities/_search?pretty -d '{
    "query": {
        "has_child" : {
            "type" : "students",
            "query" : {
                  "exists" : {"field": "firstName"}
        }
    }
}
}'

Esto da lugar a que el registro escolar (padres) aparezca:

    {
        "_index" : "universities",
        "_type" : "doc",
        "_id" : "e2cfb3b015d4be50a466aa593ab4d9f490982ede",
        "_score" : 1.0,
        "_source" : {
          "school" : "University of South Carolina - Columbia",
          "universities_students" : {
            "name" : "universities"
          }
 }

Estas publicaciones son mías y no representan necesariamente la posición, estrategias u opinión de BMC.

Más de Orquestación

¿Te interesa saber más de BMC?

El Brief están nuestro correo mensual sobre el mainframe y la orquestación empresarial: investigación, historias de clientes, noticias de productos, eventos.

Al registrarse para esta oferta te son confirmar que te leído y aceptado la Política de Privacidad de BMC.

Tú te has suscrito a The Brief

El Brief abarca la orquestación de mainframe y empresa—BMC AMI y Control-M—y la investigación de analistas, despliegues de clientes y eventos en ambas áreas.