Gestione Efficiente dei Dati con il Comando API _bulk di Elasticsearch
Utilizza correttamente l'API _bulk di Elasticsearch con esempi NDJSON, controllo delle risposte, dimensionamento dei batch e linee guida per tentativi sicuri.
Gestione Efficiente dei Dati con il Comando API _bulk di Elasticsearch
L'API _bulk di Elasticsearch è lo strumento giusto quando la tua applicazione deve indicizzare, aggiornare o eliminare molti documenti senza pagare una richiesta HTTP per ogni documento. La parte che crea confusione è il corpo della richiesta: è JSON delimitato da newline, non un array JSON ben formattato.
Usa _bulk quando carichi log, sincronizzi record da un altro database o applichi un batch di eliminazioni di pulizia. Devi comunque ispezionare ogni elemento nella risposta, perché un'operazione può fallire mentre la richiesta HTTP complessiva ha successo.
Comprendere la Struttura dell'API _bulk
L'API _bulk accetta JSON delimitato da newline, solitamente chiamato NDJSON. Ogni azione è definita su una riga. Le azioni che necessitano di un corpo del documento utilizzano la riga successiva come payload di origine o aggiornamento. Anche l'ultima riga deve terminare con un newline.
Componenti Chiave di una Richiesta _bulk:
- Riga di Azione e Metadati: Questa riga specifica il tipo di operazione (
index,create,updateodelete), l'indice di destinazione e, opzionalmente, l'ID del documento. I tipi di documento non sono utilizzati nelle moderne API Elasticsearch. - Riga di Origine: Questa riga contiene il documento JSON effettivo da indicizzare o aggiornare. Questa riga è omessa per le operazioni
delete. - Delimitatore Newline: Ogni coppia azione/metadati e la sua origine corrispondente (se applicabile) devono essere separate da un carattere newline (
\n). L'intero corpo della richiesta deve terminare con un carattere newline.
Struttura di Esempio:
{ "index": { "_index": "my-index", "_id": "1" } }
{ "field1": "value1" }
{ "delete": { "_index": "my-index", "_id": "2" } }
Oppure per un'operazione di eliminazione:
curl -sS -H 'Content-Type: application/x-ndjson' \
-X POST 'http://localhost:9200/_bulk' \
--data-binary @bulk.ndjson
Esecuzione di Operazioni Comuni con _bulk
L'API _bulk è versatile e può gestire un mix di operazioni in una singola richiesta. Qui risiede la sua vera potenza, permettendoti di eseguire manipolazioni complesse dei dati in un unico round trip.
Indicizzazione di Più Documenti
Per indicizzare più documenti, usi l'azione index. Se un documento con l'ID specificato esiste già, index lo sovrascriverà. Se vuoi assicurarti che un documento venga indicizzato solo se non esiste già, usa invece l'azione create.
Esempio: Indicizzazione di due nuovi documenti.
{ "index": { "_index": "my-index", "_id": "1" } }
{ "field1": "value1", "field2": "value2" }
{ "index": { "_index": "my-index", "_id": "2" } }
{ "field1": "another_value", "field2": "different_value" }
Aggiornamento di Documenti
L'aggiornamento dei documenti può essere fatto usando l'azione update. Specifichi l'ID del documento da aggiornare e fornisci un documento parziale con i campi che vuoi modificare. Se vuoi usare uno script per l'aggiornamento, puoi farlo all'interno dell'azione update.
Esempio: Aggiornamento di un campo in un documento esistente.
{ "update": { "_index": "my-index", "_id": "1" } }
{ "doc": { "field1": "updated_value" } }
Eliminazione di Documenti
Per eliminare documenti, usi l'azione delete, specificando _index e _id del documento da rimuovere. Non è richiesto alcun documento di origine per le operazioni di eliminazione.
Esempio: Eliminazione di un documento.
{ "delete": { "_index": "my-index", "_id": "2" } }
Combinazione di Operazioni
La vera efficienza deriva dalla combinazione di queste operazioni. Puoi indicizzare nuovi documenti, aggiornare quelli esistenti ed eliminarne altri nella stessa richiesta _bulk.
Esempio: Indicizzazione, aggiornamento ed eliminazione in una richiesta.
{ "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" } }
Gestione delle Risposte
L'API _bulk restituisce una risposta JSON che dettaglia l'esito di ogni singola operazione. È fondamentale analizzare questa risposta per verificare che tutte le operazioni siano riuscite e identificare eventuali errori.
La risposta conterrà un array items, dove ogni elemento corrisponde a una delle operazioni nella tua richiesta, nello stesso ordine. Ogni elemento includerà l'operazione index, create, update o delete, insieme al suo stato (ad es., created, updated, deleted, noop) e altri metadati rilevanti.
Esempio di Frammento di Risposta:
{
"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
}
}
]
}
Se un'operazione fallisce, il campo errors di primo livello nella risposta sarà true, e l'elemento individuale per l'operazione fallita conterrà un oggetto error che dettaglia il problema.
Migliori Pratiche e Suggerimenti
- Dimensione del Batch: Batch molto grandi possono mettere sotto pressione la memoria del client, i nodi coordinatori e i nodi dati. Inizia con payload modesti, misura il throughput e i tassi di rifiuto, poi regola in base al tuo cluster e alla dimensione dei documenti.
- Gestione degli Errori: Analizza sempre la risposta per individuare errori. Implementa una logica di ripetizione per errori transitori, se necessario.
- Delimitatori Newline: Assicurati che i caratteri newline (
\n) siano usati correttamente tra ogni oggetto JSON. Una formattazione errata è una causa comune di fallimenti dell'API_bulk. - Parallelizzazione: Per tassi di ingestione molto elevati, considera l'invio di più richieste
_bulkin parallelo, ma tieni conto della capacità del tuo cluster. createvs.index: Usacreatequando vuoi che l'operazione fallisca se l'ID esiste già. Usaindexquando è accettabile sostituire un documento esistente.- Client API: La maggior parte delle librerie client di Elasticsearch fornisce metodi convenienti per costruire ed eseguire richieste
_bulk, astraendo parte della formattazione manuale.
Conclusione Pratica
L'API _bulk è veloce perché riduce l'overhead delle richieste, ma è sicura solo quando il tuo client tratta la risposta come un elenco di risultati individuali. Invia NDJSON valido con Content-Type: application/x-ndjson, mantieni i batch a una dimensione che il tuo cluster può assorbire e ripeti solo le operazioni che sono fallite per motivi transitori.