Хобрук: Ваш путь к мастерству в программировании

Почему в mongodb быстрее запрашивать индексированный массив вложенных документов, чем индексированные документы первого уровня?

Вот так выглядит моя база данных:

> show dbs
admin   0.203125GB
local   0.078125GB
profiler    63.9228515625GB
> use profiler
switched to db profiler
> show collections
documents
mentions

Документ в упоминаниях выглядит так:

> db.mentions.findOne()
{
    "_id" : ObjectId("51ec29ef1b63042f6a9c6fd2"),
    "corpusID" : "GIGAWORD",
    "docID" : "WPB_ENG_20100226.0044",
    "url" : "http://en.wikipedia.org/wiki/Taboo",
    "mention" : "taboos",
    "offset" : 4526
}

Документ в документах выглядит так:

> db.documents.findOne()
{
    "_id" : ObjectId("51ec2d981b63042f6ae4ca0b"),
    "sentence_offsets" : [
        ..................
    ],
    "docID" : "WPB_ENG_20101020.0002",
    "text" : ".........",
    "verb_offsets" : [
    .............
    ],
    "mentions" : [
        {
            "url" : "http://en.wikipedia.org/wiki/Washington,_D.C.",
            "mention" : "Washington",
            "ner" : "ORG",
            "offset" : 122
        },
        ...................
    ],
    "corpusID" : "GIGAWORD",
    "chunk_offsets" : [
        .................
    ]
}

В упоминаниях 100 миллионов документов и 1,3 миллиона в документах. Каждое упоминание, появляющееся в mentions, также должно один раз появляться в массиве mentions некоторого document. Причина, по которой я сохраняю информацию об упоминаниях в документах, заключалась в том, чтобы не обращаться к упоминаниям для извлечения контекста. Тем не менее, когда я запрашиваю только упоминания, я подумал, что будет быстрее иметь независимую коллекцию, mentions.

Однако после того, как я поэкспериментировал с индексом как для mentions.url/mentions.mention, так и для documents.mentions.url/documents.mentions.mention и запросил один и тот же URL/упоминание в обеих коллекциях, я обнаружил, что получить ответ из коллекции документов было в два раза быстрее, чем из коллекции упоминаний.

Я не уверен, как индекс работает внутри, но я предполагаю, что оба индекса имеют одинаковый размер, поскольку в обеих коллекциях одинаковое количество упоминаний. Таким образом, они должны иметь одинаковое время отклика?

Я пытался что-то вроде

> db.mentions.find({url: "http://en.wikipedia.org/wiki/Washington,_D.C."}).explain()

поэтому не должно быть разницы в сетевых накладных расходах.

Вот результат

> db.mentions.find({mention: "Illinois"}).explain()

{
"cursor" : "BtreeCursor mention_1",
"isMultiKey" : false,
"n" : 4342,
"nscannedObjects" : 4342,
"nscanned" : 4342,
"nscannedObjectsAllPlans" : 4342,
"nscannedAllPlans" : 4342,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 14,
"nChunkSkips" : 0,
"millis" : 18627,
"indexBounds" : {
    "mention" : [
        [
            "Illinois",
            "Illinois"
        ]
    ]
},
"server" : "----:----"
}

и что из

> db.documents.find({"mentions.mention": "Illinois"}).explain()

{
"cursor" : "BtreeCursor mentions.mention_1",
"isMultiKey" : true,
"n" : 3102,
"nscannedObjects" : 3102,
"nscanned" : 3102,
"nscannedObjectsAllPlans" : 3102,
"nscannedAllPlans" : 3102,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 8,
"nChunkSkips" : 0,
"millis" : 7862,
"indexBounds" : {
    "mentions.mention" : [
        [
            "Illinois",
            "Illinois"
        ]
    ]
},
"server" : "----:----"
}

И статистика (ага, я восстановил коллекцию и еще не проиндексировал document.url):

> db.documents.stats()
{
    "ns" : "profiler.documents",
    "count" : 1302957,
    "size" : 23063622656,
    "avgObjSize" : 17700.985263519826,
    "storageSize" : 25188048768,
    "numExtents" : 31,
    "nindexes" : 2,
    "lastExtentSize" : 2146426864,
    "paddingFactor" : 1,
    "systemFlags" : 1,
    "userFlags" : 0,
    "totalIndexSize" : 3432652720,
    "indexSizes" : {
        "_id_" : 42286272,
        "mentions.mention_1" : 3390366448
    },
    "ok" : 1
}
> db.mentions.stats()
{
    "ns" : "profiler.mentions",
    "count" : 97458884,
    "size" : 15299979084,
    "avgObjSize" : 156.98906509128506,
    "storageSize" : 17891127216,
    "numExtents" : 29,
    "nindexes" : 3,
    "lastExtentSize" : 2146426864,
    "paddingFactor" : 1,
    "systemFlags" : 0,
    "userFlags" : 0,
    "totalIndexSize" : 15578411408,
    "indexSizes" : {
        "_id_" : 3162125232,
        "mention_1" : 4742881248,
        "url_1" : 7673404928
    },
    "ok" : 1
}

Буду признателен, если кто-нибудь скажет мне, почему это происходит. :]


  • Можете ли вы поделиться выводом для следующего: 1) вывод объяснения для ваших двух запросов 2) db.collection.stats() для ваших двух коллекций? 03.08.2013
  • Дилан, извините за поздний ответ. Я обновил вопрос выводом объяснения () и статистики () для коллекций. Кроме того, я добавил некоторые дополнительные исследования в ответ Аси. Какие-нибудь мысли? 07.09.2013
  • План выполнения показывает мне две причины, по которым одна работает быстрее другой. Отмечено, что они могут быть не единственной причиной. Прежде всего, ваш индекс поддокументов имеет на 33% большую избирательность. На другом вы сканируете и извлекаете на 33 % больше документов. Производительность ухудшается еще больше в результате более длительного выполнения запроса. Обратите внимание, что ваш первый запрос дает 14 раз по сравнению с 8 по другому. Это означает, что ваш первый запрос приводит к большему количеству операций записи, или это может даже быть индикатором того, что рабочий набор вашего индекса не находится в памяти, и он дает сбой, что приводит к увеличению производительности. 07.09.2013

Ответы:


1

В упоминаниях 100 миллионов документов и 1,3 миллиона в документах.

В обоих указателях одинаковое количество записей, потому что вы сказали нам, что храните упоминания как в документах, так и в упоминаниях.

Таким образом, время доступа к индексу одинаково. Вы можете измерить это, запустив покрытый запрос индекса из обоих, что означает, что вы хотите получить только значения, которые хранятся в индексе: db.x.find({url:"xxx"}, {_id:0, "url":1}) говорит, что найдите соответствующий документ и верните только значение URL из него. Если эти два значения не равны для двух подключений, возможно, что-то не так с вашей настройкой, или один из индексов не помещается в ОЗУ, или другая проблема, связанная с измерением.

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

06.09.2013
  • Спасибо Ася. В коллекции упоминаний и коллекции документов должно быть одинаковое количество упоминаний. Однако, согласно выводу collection.stats(), который я только что добавил к вопросу, размер индекса mention_1 более чем на 1/3 больше, чем у mentions.mention_1. И когда я делаю watch -n 1 free -m, кажется, что запрос колл упоминаний занимает вдвое больше места в ОЗУ, чем колл документов. 07.09.2013
  • Хотя документ в списке документов определенно больше, чем документ в списке упоминаний, количество совпадающих документов в списке документов намного меньше, чем в списке упоминаний. Итак, может быть, монго загружает результаты в ОЗУ по запросу, а общий размер результатов из списка документов оказывается вдвое меньше, чем из списка упоминаний? 07.09.2013
  • Оказалось, что db.documents.find({"mentions.mention":"China"}, {_id:1}).explain() дает mills: 98502, а db.mentions.find({"mention":"China"}, {_id:1}).explain() дает mills: 134932. Смущенный. 07.09.2013
  • Новые материалы

    React on Rails
    Основное приложение Reverb - это всеми любимый монолит Rails. Он отлично обслуживает наш API и уровень просмотра трафика. По мере роста мы добавляли больше интерактивных элементов..

    Что такое гибкие методологии разработки программного обеспечения
    Что представляют собой гибкие методологии разработки программного обеспечения в 2023 году Agile-методологии разработки программного обеспечения заключаются в следующем: И. Введение A...

    Ториго  — революция в игре Го
    Наш следующий вызов против ИИ и для ИИ. Сможет ли он победить людей в обновленной игре Го? Обратите внимание, что в следующей статье AI означает искусственный интеллект, а Goban  —..

    Простое развертывание моделей с помощью Mlflow — Упаковка классификатора обзоров продуктов NLP от HuggingFace
    Как сохранить свои модели машинного обучения в формате с открытым исходным кодом с помощью MLFlow, чтобы позже получить возможность легкого развертывания. Сегодня модели упаковки имеют несколько..

    Математика и интуиция - Часть 1
    У каждой математической формулы есть доказательство. Часто эти доказательства слишком сложно понять, поскольку многие из них основаны на индукции, некоторые - на очень сложных наблюдениях, а..

    Раскрытие возможностей НЛП: часть речевой маркировки и ее проблемы
    В сфере обработки естественного языка (NLP) маркировка частей речи (POS) выступает в качестве фундаментального метода, позволяющего компьютерам понимать и анализировать человеческий язык на..

    Под поверхностью: раскрытие деталей системы с помощью инструментов Linux CLI
    Чем больше вы изучаете Linux и продвигаетесь вперед, тем больше вам нужно проверять информацию о вашей системе. Эта информация может касаться аппаратного обеспечения, такого как процессор,..