Загрузка нерегулярных json в индекс Elasticsearch с отображением с помощью клиента Python - PullRequest
0 голосов
/ 28 марта 2020

У меня есть некоторые. json, где не все поля присутствуют во всех записях, например, caseclass.json выглядит следующим образом:

[{
    "name" : "john smith", 
    "age" : 12, 
    "cars": ["ford", "toyota"], 
    "comment": "i am happy"
},
{
    "name": "a. n. other", 
    "cars": "", 
    "comment": "i am panicking"
}]

Использование Elasticsearch-7.6.1 через python client эластичный поиск:

from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search
import json
import os
from elasticsearch_dsl import Document, Text, Date, Integer, analyzer

es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
class Person(Document):
        class Index:
            using = es
            name = 'person_index'
        name = Text()
        age = Integer()
        cars = Text()
        comment = Text(analyzer='snowball')   

Person.init()

with open ("caseclass.json") as json_file:
data = json.load(json_file)
for indexid in range(len(data)):
    document = Person(name=data[indexid]['name'], age=data[indexid]['age'], cars=data[indexid]['cars'], comment=data[indexid]['comment'])
    document.meta.id = indexid
    document.save()

Естественно, я получаю KeyError: 'age', когда вторая запись пытается быть прочитанной. Мой вопрос: возможно ли загрузить такие записи в индекс Elasticsearch, используя клиент Python и предопределенное отображение вместо отображения Dynami c? Вышеприведенный код работает, если все поля присутствуют во всех записях, но есть ли способ сделать это, не проверяя наличие каждого поля в записи, поскольку реальные записи имеют сложную структуру и их миллионы? Спасибо

1 Ответ

0 голосов
/ 28 марта 2020

Ошибка не имеет ничего общего с вашим отображением - она ​​просто сообщает вам, что age не может быть доступен в одном из ваших caseclasses.

Отображение индекса создается при вызове Person.init() - вы можете проверить это, позвонив print(es.indices.get_mapping(Person.Index.name)) сразу после Person.init().

Я немного почистил ваш код:

import json
import os
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search, Document, Text, Date, Integer, analyzer

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


class Person(Document):
    class Index:
        using = es
        name = 'person_index'
    name = Text()
    age = Integer()
    cars = Text()
    comment = Text(analyzer='snowball')


Person.init()
print(es.indices.get_mapping(Person.Index.name))

with open("caseclass.json") as json_file:
    data = json.load(json_file)
    for indexid, case in enumerate(data):
        document = Person(**case)
        document.meta.id = indexid
        document.save()

Обратите внимание, как я использовал **case чтобы распределить все пары ключ-значение внутри case вместо использования data[property_key].

Сгенерированное отображение выглядит следующим образом:

{
  "person_index" : {
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "integer"
        },
        "cars" : {
          "type" : "text"
        },
        "comment" : {
          "type" : "text",
          "analyzer" : "snowball"
        },
        "name" : {
          "type" : "text"
        }
      }
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...