2016-09-14 4 views
0

Я унаследовал старую базу данных Mongo. Давайте сосредоточимся на следующих двух сборниках (удалили большую часть их содержания для лучшей читаемости):Как повысить производительность запросов pymongo

пользователя Коллекция

db.user.find_one({"email": "[email protected]"}) 

{'lastUpdate': datetime.datetime(2016, 9, 2, 11, 40, 13, 160000), 
'creationTime': datetime.datetime(2016, 6, 23, 7, 19, 10, 6000), 
'_id': ObjectId('576b8d6ee4b0a37270b742c7'), 
'email': '[email protected]' } 

Коллекции входа (один пользователь много записей):

db.entry.find_one({"userId": _id}) 

{'date_entered': datetime.datetime(2015, 2, 7, 0, 0), 
'creationTime': datetime.datetime(2015, 2, 8, 14, 41, 50, 701000), 
'lastUpdate': datetime.datetime(2015, 2, 9, 3, 28, 2, 115000), 
'_id': ObjectId('54d775aee4b035e584287a42'), 
'userId': '576b8d6ee4b0a37270b742c7', 
'data': 'test'} 

Как вы можете видеть, между ними нет DBRef.

Что я хотел бы сделать, это подсчитать общее количество записей и количество записей, обновленных после указанной даты.

Для этого я использовал библиотеку pymongo Python. В приведенном ниже коде мне нужны все, что мне нужно, но это очень медленно.

from pymongo import MongoClient 
client = MongoClient('mongodb://foobar/') 
db = client.userdata 

# First I need to fetch all user ids. Otherwise db cursor will time out after some time. 
user_ids = [] # build a list of tuples (email, id) 
for user in db.user.find(): 
    user_ids.append((user['email'], str(user['_id']))) 

date = datetime(2016, 1, 1) 
for user_id in user_ids: 
    email, _id = user_id 

    t0 = time.time() 

    query = {"userId": _id} 
    no_of_all_entries = db.entry.find(query).count() 

    query = {"userId": _id, "lastUpdate": {"$gte": date}} 
    no_of_entries_this_year = db.entry.find(query).count() 

    t1 = time.time() 
    print("delay ", round(t1 - t0, 2)) 

    print(email, no_of_all_entries, no_of_entries_this_year) 

Она занимает около 0,83 секунды, чтобы запустить оба db.entry.find запросов на моем ноутбуке, и 0,54 на сервере AWS (не сервера MongoDB).

Имея ~ 20000 пользователей, для получения всех данных требуется 3 часа. Это та латентность, которую вы ожидаете увидеть в Монго? Что я могу сделать, чтобы улучшить это? Имейте в виду, что MongoDB является для меня совершенно новым.

ответ

1

Вместо запуска двух агрегатов для всех пользователей отдельно вы можете просто получить оба агрегата для всех пользователей с помощью db.collection.aggregate().

И вместо кортежей (email, userId) мы делаем это как словарь, так как его легче использовать для получения соответствующего электронного письма.

user_emails = {str(user['_id']): user['email'] for user in db.user.find()} 

date = datetime(2016, 1, 1) 
entry_counts = db.entry.aggregate([ 
    {"$group": { 
     "_id": "$userId", 
     "count": {"$sum": 1}, 
     "count_this_year": { 
      "$sum": { 
       "$cond": [{"$gte": ["$lastUpdate", date]}, 1, 0] 
      } 
     } 
    }} 
]) 

for entry in entry_counts: 
    print(user_emails.get(entry['_id']), 
      entry['count'], 
      entry['count_this_year']) 

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

+0

Спасибо. Однако не только объект CommandCursor не имеет атрибутов 'values', но также len (list (entry_counts)) == 0. Возможно, версия MongoDB у меня слишком старческая? –

+0

О, черт побери. Нет, это просто опечатка. Сожалею. Я исправлю это. – Sevanteri

+0

Теперь исправлено. И хм, не уверен, что на entry_counts пусто. Возможно, мои данные тестирования были немного разными. – Sevanteri

 Смежные вопросы

  • Нет связанных вопросов^_^