Tark
@Tark
Pyramid'альный мир

Как оптимизировать пересечение списка значений MongoDB?

Здравствуйте.

Цель скрипта - поиск по токенам. Всё это дело работает под Python (фреймворк Flask) + MongoDB и установлено на VDS с 400 мегабайт памяти, поэтому ставить Sphinx очень бы не хотелось, проще тогда вообще убрать поиск, тем более что смысла в нём особенного нет.

Коллекция в Mongo имеет вид
{
    "token": "слово",
    "haystack": {
        "тип": [список ключей],
        "тип2": [список ключей2]
    }
}

То есть для поиска собственно документов нужно сделать запрос к базе, а после - сделать пересечение списков одного типа. К сожалению, аггрегация в этом случае вообще никак не поможет (используется MongoDB версии 2.4.9, ключ $setIntersection в блоке $project появится в MongoDB 2.6)

Пока используется следующий код:

def intersect(array):
    def intersection(a, b):
        if not a or not b:
            return []
        return list(set(a).intersection(b))

    ret = {}
    for val in array:
        if not ret:  # если первый словарь
            ret = val['haystack']
        else:
            current = val['haystack']
            ret = {
                'goods': intersection(ret.get('goods'), current.get('goods')),
                'pages': intersection(ret.get('pages'), current.get('pages')),
                'news': intersection(ret.get('news'), current.get('news'))
            }
    return ret

Если получаемые списки небольшие - всё отрабатывается за миллисекунды. Но в текущей базе порядка 10К записей и при этом токенов слишком мало, каждый документ содержит в себе до 7 тысяч значений. Интересно, что получение данных при следующем вызове занимает 63 мс (два документа, 1597 и 6602 значений списка, после пересечения получается список из 1448 элементов)

result = list(db.search.find({'token': {'$in': tokens}}))

...а пересечение списков добавляет... всего миллисекунду. Хм.

В связи с этим есть вопрос: нельзя ли как-нибудь ускорить это дело?

Индекс по токенам есть, само собой, тот же запрос с .explain() в консоли mongo утверждает, что выполняется за минимальное время - 0 мс. Но почему возвращаются эти результаты ТАК ДОЛГО? Что можно сделать в таком странном случае?
  • Вопрос задан
  • 3200 просмотров
Решения вопроса 1
Tark
@Tark Автор вопроса
Pyramid'альный мир
Мда. Использовался драйвер pymongo версии 2.5.2. Установил последний, 2.6.3, время получения данных сократилось до 3 мс, с пересечением - до 4 мс. Результат считаю удовлетворительным, а вопрос - закрытым. Эх!
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы