Вчера, по-сути, завершил проект high-perf-bio, реализовав в left_join отбор геномных интервалов одной MongoDB-коллекции по их вхождению/невхождению в интервалы из других коллекций БД. Но, как выяснилось, не без ложки дёгтя.
Пояснение для IT-специалистов, не специализирующихся на работе с генетическими данными. Что такое геномный интервал? Есть хромосомы - надмолекулярные сткуктуры, включающие, помимо всего прочего, ДНК. Есть нуклеотиды - мономеры ДНК. Сослаться на тот или иной участок ДНК можно так: обозначение хромосомы, номер стартового нуклеотида, номер конечного нуклеотида. Эти два нуклеотида - границы как раз геномного интервала. В биоинформатических таблицах чаще всего мы видим интервалы с выявленным влиянием на организм.
Aggregation pipeline из программы left_join, построенный по официальным докам MongoDB, выдаёт правильные результаты, но работает бесконечно долго для больших коллекций. Ни compound, ни одиночные индексы не ускоряют вычисление. Вот основа пайплайна - код левостороннего внешнего объединения коллекций - источника описываемой проблемы:
pipeline = [{'$lookup': {'from': right_coll_name,
'let': {'chrom': '$chrom', 'start': '$start', 'end': '$end'},
'pipeline': [{'$match': {'$expr': {'$and': [{'$eq': ['$$chrom', '$chrom']},
{'$lt': [{'$max': ['$$start', '$start']},
{'$min': ['$$end', '$end']}]}]}}}],
'as': right_coll_name.replace('.', '_')}} for right_coll_name in right_coll_names]
Эта же конструкция, но чуть упрощённая (Ilya Vorontsov):
pipeline = [{'$lookup': {'from': right_coll_name,
'let': {'chrom': '$chrom', 'start': '$start', 'end': '$end'},
'pipeline': [{'$match': {'$expr': {'$and': [{'$eq': ['$$chrom', '$chrom']},
{'$lt': ['$$start', '$end']},
{'$lt': ['$start', '$$end']}]}}}],
'as': right_coll_name.replace('.', '_')}} for right_coll_name in right_coll_names]
Каждый объединённый документ представляет собой документ "левой" коллекции, в который вложены отвечающие запросу документы "правых" коллекций. Если в "правой" коллекции не нашлось соответствий, в объединённый документ попадает пустой список.
Кто-нибудь знает, как решить/обойти проблему игнора индексов?
P.S. Я уже создал аналогичную тему на официальном форуме MongoDB, но там далеко не всегда отвечают. Поэтому очень надеюсь на помощь коллег, знакомых и других посетителей репозитория.
@VorontsovIE, @yustinaivanova, может у вас будут какие-то идеи? Был бы очень благодарен.
Предполагаемые тормозящие факторы:
- Вложенный пайплайн, какое бы выражение в нём ни было. UPD: точно нет: если попробовать объединять аналогичной конструкцией не по интервалам, а по одиночным полям, то всё посчитается почти мгновенно.
- Подсчёт максимальной стартовой границы и минимальной конечной (Ilya Vorontsov).
- Сочетание работы по хромосомам с работой по интеравалам.
- Добавляемая к
$lookup
-пайплайну сортировка. Сразу говорю, что она не влияет.