Вставьте тысячи объектов в разумное время в 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 в значительной степени бессмысленен - думайте об этом как об отладчике больше, чем что-либо еще!