web-dev-qa-db-fra.com

Comment utiliser l'API en bloc pour stocker les mots-clés dans ES en utilisant Python

Je dois stocker un message dans ElasticSearch intégré à mon programme python. Maintenant, ce que j'essaie de stocker le message est:

d={"message":"this is message"}
    for index_nr in range(1,5):
        ElasticSearchAPI.addToIndex(index_nr, d)
        print d

Cela signifie que si j'ai 10 messages, je dois répéter mon code 10 fois. Donc, ce que je veux faire, c'est essayer de créer un fichier script ou un fichier batch . J'ai vérifié le ElasticSearch Guide , il est possible d'utiliser l'API BULK. Le format devrait être quelque chose comme ci-dessous:

{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "type1", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "type1", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "type1", "_index" : "index1"} }
{ "doc" : {"field2" : "value2"} }

ce que j'ai fait c'est: 

{"index":{"_index":"test1","_type":"message","_id":"1"}}
{"message":"it is red"}
{"index":{"_index":"test2","_type":"message","_id":"2"}}
{"message":"it is green"}

J'utilise également l'outil curl pour stocker la doc. 

$ curl -s -XPOST localhost:9200/_bulk --data-binary @message.json

Maintenant, je veux utiliser mon code Python pour stocker le fichier dans Elastic Search.

43
chengji18
from datetime import datetime

from elasticsearch import Elasticsearch
from elasticsearch import helpers

es = Elasticsearch()

actions = [
  {
    "_index": "tickets-index",
    "_type": "tickets",
    "_id": j,
    "_source": {
        "any":"data" + str(j),
        "timestamp": datetime.now()}
  }
  for j in range(0, 10)
]

helpers.bulk(es, actions)
90
Justina Chen

Bien que le code de @justinachen m’ait aidé à démarrer py-elasticsearch, après avoir consulté le code source, m’a apporté une amélioration simple:

es = Elasticsearch()
j = 0
actions = []
while (j <= 10):
    action = {
        "_index": "tickets-index",
        "_type": "tickets",
        "_id": j,
        "_source": {
            "any":"data" + str(j),
            "timestamp": datetime.now()
            }
        }
    actions.append(action)
    j += 1

helpers.bulk(es, actions)

helpers.bulk() fait déjà la segmentation pour vous. Et par segmentation, j'entends les mandrins envoyés à chaque fois au serveur. Si vous souhaitez réduire le nombre de documents envoyés, procédez comme suit: helpers.bulk(es, actions, chunk_size=100)

Quelques informations utiles pour commencer: 

helpers.bulk() est juste un wrapper du helpers.streaming_bulk mais le premier accepte une liste qui le rend pratique.

helpers.streaming_bulk est basé sur Elasticsearch.bulk(), vous n'avez donc pas à vous soucier de ce qu'il faut choisir.

Donc, dans la plupart des cas, helpers.bulk () devrait suffire.

41
Diolor

(Les autres approches mentionnées dans ce fil utilisent python list pour la mise à jour de ES, ce qui n'est pas une bonne solution aujourd'hui, surtout lorsque vous devez ajouter des millions de données à ES)

Une meilleure approche utilise des générateurs python - traiter des concerts de données sans épuiser la mémoire ni compromettre la vitesse d'exécution}.

Vous trouverez ci-dessous un exemple d'extrait de cas d'utilisation pratique: ajout de données du fichier journal nginx à ES pour analyse.

def decode_nginx_log(_nginx_fd):
    for each_line in _nginx_fd:
        # Filter out the below from each log line
        remote_addr = ...
        timestamp   = ...
        ...

        # Index for elasticsearch. Typically timestamp.
        idx = ...

        es_fields_keys = ('remote_addr', 'timestamp', 'url', 'status')
        es_fields_vals = (remote_addr, timestamp, url, status)

        # We return a dict holding values from each line
        es_nginx_d = dict(Zip(es_fields_keys, es_fields_vals))

        # Return the row on each iteration
        yield idx, es_nginx_d   # <- Note the usage of 'yield'

def es_add_bulk(nginx_file):
    # The nginx file can be gzip or just text. Open it appropriately.
    ...

    es = Elasticsearch(hosts = [{'Host': 'localhost', 'port': 9200}])

    # NOTE the (...) round brackets. This is for a generator.
    k = ({
            "_index": "nginx",
            "_type" : "logs",
            "_id"   : idx,
            "_source": es_nginx_d,
         } for idx, es_nginx_d in decode_nginx_log(_nginx_fd))

    helpers.bulk(es, k)

# Now, just run it.
es_add_bulk('./nginx.1.log.gz')

Ce squelette illustre l'utilisation des générateurs. Vous pouvez l'utiliser même sur une machine nue si vous en avez besoin. Et vous pouvez continuer à développer ceci pour adapter rapidement à vos besoins.

Python Elasticsearch référence ici .

30
Ethan

Définir le nom de l'index et le type de document avec chaque entité:

es_client = Elasticsearch()

body = []
for entry in entries:
    body.append({'index': {'_index': index, '_type': 'doc', '_id': entry['id']}})
    body.append(entry)

response = es_client.bulk(body=body)

Indiquez l'index par défaut et le type de document avec la méthode:

es_client = Elasticsearch()

body = []
for entry in entries:
    body.append({'index': {'_id': entry['id']}})
    body.append(entry)

response = es_client.bulk(index='my_index', doc_type='doc', body=body)

Marche avec:

Version ES: 6.4.0

ES python lib: 6.3.1

1
Rafal Enden