Вставьте тысячи объектов в разумное время в BigTable

У меня возникают некоторые проблемы, когда я пытаюсь вставить 36k французских городов в BigTable. Я анализирую файл CSV и помещаю каждую строку в хранилище данных, используя этот фрагмент кода:

import csv
from databaseModel import *
from google.appengine.ext.db import GqlQuery

def add_cities():
spamReader = csv.reader(open('datas/cities_utf8.txt', 'rb'), delimiter='\t', quotechar='|')
mylist = []
for i in spamReader:
    region = GqlQuery("SELECT __key__ FROM Region WHERE code=:1", i[2].decode("utf-8"))
    mylist.append(InseeCity(region=region.get(), name=i[11].decode("utf-8"), name_f=strip_accents(i[11].decode("utf-8")).lower()))
db.put(mylist)

Это займет около 5 минут (!!!), чтобы сделать это с локальным сервером разработки, и даже 10 минут при удалении их с помощью функции db.delete(). Когда я пробую онлайн, вызывая страницу test.py, содержащую add_cities(), истекает тайм-аут 30 секунд. Я из мира MySQL и считаю, что стыдно не добавлять 36 тыс. Сущностей менее чем за секунду. Я могу ошибаться в способе сделать это, поэтому я ссылаюсь на вас:

  • Почему это так медленно?
  • Есть ли способ сделать это в разумные сроки?

Спасибо:)

3 ответа

Решение

Во-первых, это хранилище данных, а не Bigtable. В хранилище данных используется bigtable, но к этому добавляется гораздо больше.

Основная причина, по которой это происходит так медленно, заключается в том, что вы делаете запрос (по типу "Регион") для каждой добавляемой вами записи. Это неизбежно существенно замедлит ход событий. Есть две вещи, которые вы можете сделать, чтобы ускорить процесс:

  • Использовать code из Region как его key_name, что позволяет вам быстрее получать данные из хранилища вместо запроса. Фактически, поскольку вам нужен только ключ региона для ссылочного свойства, в этом случае вам вообще не нужно извлекать регион.
  • Кэшируйте список регионов в памяти или вообще не сохраняйте его в хранилище данных. По своей природе я предполагаю, что регионы - это и небольшой список, и изменяющиеся нечасто, поэтому, возможно, нет необходимости хранить его в хранилище данных.

Кроме того, вы должны использовать каркас mapreduce при загрузке больших объемов данных, чтобы избежать тайм-аутов. Он также имеет встроенную поддержку для чтения CSV-файлов из BLOB-магазинов.

Используйте очередь задач. Если вы хотите, чтобы ваш набор данных обрабатывался быстро, обработчик загрузки должен создать задачу для каждого подмножества 500, используя значение смещения.

FWIW мы обрабатываем большие CSV в хранилище данных, используя mapreduce, с некоторой начальной обработкой / проверкой внутри задачи. Даже задачи имеют ограничение (10 минут) на данный момент, но это, вероятно, хорошо для вашего размера данных.

Убедитесь, что вы делаете вставки и т. Д. вы пакетируете как можно больше - не вставляете отдельные записи, и то же самое для поисков - get_by_keyname позволяет передавать массив ключей. (Я полагаю, что на данный момент db put имеет ограничение в 200 записей?)

Mapreduce может быть излишним для того, что вы делаете сейчас, но это определенно стоит обдумать, это необходимо для больших наборов данных.

Наконец, выбор времени для чего-либо в SDK в значительной степени бессмысленен - ​​думайте об этом как об отладчике больше, чем что-либо еще!

Другие вопросы по тегам