Gestión eficiente de datos con el comando _bulk API de Elasticsearch
Utiliza correctamente la API _bulk de Elasticsearch con ejemplos NDJSON, verificación de respuestas, tamaño de lotes y guía de reintentos seguros.
Gestión eficiente de datos con el comando _bulk API de Elasticsearch
La API _bulk de Elasticsearch es la herramienta adecuada cuando tu aplicación necesita indexar, actualizar o eliminar muchos documentos sin pagar por una solicitud HTTP por documento. La parte que confunde a la gente es el cuerpo de la solicitud: es JSON delimitado por saltos de línea, no un arreglo JSON bonito.
Usa _bulk cuando estés cargando registros, sincronizando registros de otra base de datos o aplicando un lote de eliminaciones de limpieza. Aún necesitas inspeccionar cada elemento en la respuesta, porque una operación puede fallar mientras la solicitud HTTP general tiene éxito.
Entendiendo la estructura de la API _bulk
La API _bulk acepta JSON delimitado por saltos de línea, generalmente llamado NDJSON. Cada acción se define en una línea. Las acciones que necesitan un cuerpo de documento usan la siguiente línea como fuente o carga útil de actualización. La línea final también debe terminar con un salto de línea.
Componentes clave de una solicitud _bulk:
- Línea de acción y metadatos: Esta línea especifica el tipo de operación (
index,create,updateodelete), el índice de destino y opcionalmente el ID del documento. Los tipos de documento no se utilizan en las API modernas de Elasticsearch. - Línea de origen: Esta línea contiene el documento JSON real que se va a indexar o actualizar. Esta línea se omite para las operaciones
delete. - Delimitador de salto de línea: Cada par de acción/metadatos y su origen correspondiente (si aplica) deben estar separados por un carácter de salto de línea (
\n). Todo el cuerpo de la solicitud debe terminar con un carácter de salto de línea.
Estructura de ejemplo:
{ "index": { "_index": "my-index", "_id": "1" } }
{ "field1": "value1" }
{ "delete": { "_index": "my-index", "_id": "2" } }
O para una operación de eliminación:
curl -sS -H 'Content-Type: application/x-ndjson' \
-X POST 'http://localhost:9200/_bulk' \
--data-binary @bulk.ndjson
Realizando operaciones comunes con _bulk
La API _bulk es versátil y puede manejar una mezcla de operaciones dentro de una sola solicitud. Aquí es donde reside su verdadero poder, permitiéndote realizar manipulaciones complejas de datos en un solo viaje de ida y vuelta.
Indexando múltiples documentos
Para indexar múltiples documentos, usas la acción index. Si un documento con el ID especificado ya existe, index lo sobrescribirá. Si quieres asegurarte de que un documento solo se indexe si no existe, usa la acción create en su lugar.
Ejemplo: Indexando dos documentos nuevos.
{ "index": { "_index": "my-index", "_id": "1" } }
{ "field1": "value1", "field2": "value2" }
{ "index": { "_index": "my-index", "_id": "2" } }
{ "field1": "another_value", "field2": "different_value" }
Actualizando documentos
La actualización de documentos se puede hacer usando la acción update. Especificas el ID del documento a actualizar y proporcionas un documento parcial con los campos que deseas cambiar. Si quieres usar un script para la actualización, puedes hacerlo dentro de la acción update.
Ejemplo: Actualizando un campo en un documento existente.
{ "update": { "_index": "my-index", "_id": "1" } }
{ "doc": { "field1": "updated_value" } }
Eliminando documentos
Para eliminar documentos, usas la acción delete, especificando el _index y _id del documento a eliminar. No se requiere documento de origen para las operaciones de eliminación.
Ejemplo: Eliminando un documento.
{ "delete": { "_index": "my-index", "_id": "2" } }
Combinando operaciones
La verdadera eficiencia proviene de mezclar estas operaciones. Puedes indexar nuevos documentos, actualizar existentes y eliminar otros, todo en la misma solicitud _bulk.
Ejemplo: Indexando, actualizando y eliminando en una sola solicitud.
{ "index": { "_index": "my-index", "_id": "3" } }
{ "field1": "new_document_field", "field2": "new_document_value" }
{ "update": { "_index": "my-index", "_id": "1" } }
{ "doc": { "field1": "further_updated_value" } }
{ "delete": { "_index": "my-index", "_id": "2" } }
Manejo de respuestas
La API _bulk devuelve una respuesta JSON que detalla el resultado de cada operación individual. Es crucial analizar esta respuesta para verificar que todas las operaciones fueron exitosas e identificar cualquier error.
La respuesta contendrá un arreglo items, donde cada elemento corresponde a una de las operaciones en tu solicitud, en el mismo orden. Cada elemento incluirá la operación index, create, update o delete, junto con su estado (por ejemplo, created, updated, deleted, noop) y otros metadatos relevantes.
Fragmento de respuesta de ejemplo:
{
"took": 150,
"errors": false,
"items": [
{
"index": {
"_index": "my-index",
"_id": "3",
"version": 1,
"result": "created",
"_shards": {"total": 2, "successful": 1, "failed": 0},
"_seq_no": 0,
"_primary_term": 1
}
},
{
"update": {
"_index": "my-index",
"_id": "1",
"version": 2,
"result": "updated",
"_shards": {"total": 2, "successful": 1, "failed": 0},
"_seq_no": 1,
"_primary_term": 1
}
},
{
"delete": {
"_index": "my-index",
"_id": "2",
"version": 2,
"result": "deleted",
"_shards": {"total": 2, "successful": 1, "failed": 0},
"_seq_no": 2,
"_primary_term": 1
}
}
]
}
Si alguna operación falla, el campo errors de nivel superior en la respuesta será true, y el elemento individual para la operación fallida contendrá un objeto error detallando el problema.
Mejores prácticas y consejos
- Tamaño del lote: Los lotes muy grandes pueden sobrecargar la memoria del cliente, los nodos coordinadores y los nodos de datos. Comienza con cargas útiles modestas, mide el rendimiento y las tasas de rechazo, luego ajusta según tu clúster y el tamaño del documento.
- Manejo de errores: Siempre analiza la respuesta en busca de errores. Implementa lógica de reintento para errores transitorios si es necesario.
- Delimitadores de salto de línea: Asegúrate de que los caracteres de salto de línea (
\n) se usen correctamente entre cada objeto JSON. Un formato incorrecto es una causa común de fallos en la API_bulk. - Paralelización: Para tasas de ingesta muy altas, considera enviar múltiples solicitudes
_bulken paralelo, pero ten en cuenta la capacidad de tu clúster. createvs.index: Usacreatecuando quieras que la operación falle si el ID ya existe. Usaindexcuando sea aceptable reemplazar un documento existente.- Clientes API: La mayoría de las bibliotecas cliente de Elasticsearch proporcionan métodos convenientes para construir y ejecutar solicitudes
_bulk, abstrayendo parte del formato manual.
Conclusión práctica
La API _bulk es rápida porque reduce la sobrecarga de solicitudes, pero solo es segura cuando tu cliente trata la respuesta como una lista de resultados individuales. Envía NDJSON válido con Content-Type: application/x-ndjson, mantén los lotes en un tamaño que tu clúster pueda absorber, y reintenta solo las operaciones que fallaron por razones transitorias.