Опубликован: 05.01.2015 | Доступ: свободный | Студентов: 1996 / 0 | Длительность: 63:16:00
Лекция 16:

Внешний поиск

Алгоритмы поиска, которые могут выбирать элементы из больших файлов, имеют огромное практическое значение. Поиск — это основная операция для больших наборов данных, которая, безусловно, задействует значительную часть ресурсов, используемых во многих вычислительных средах. С появлением глобальных сетей появилась возможность выбирать практически любую информацию, хоть как-то относящуюся к какой-либо задаче — проблема заключается только в возможности эффективного поиска. В этой главе рассматриваются базовые механизмы, которые могут поддерживать эффективный поиск в настолько больших таблицах символов, насколько можно себе представить.

Подобно алгоритмам из "Специальные методы сортировки" , алгоритмы, рассматриваемые в этой главе, пригодны для множества различных типов аппаратных и программных сред. Поэтому мы будем стремиться к формулировке алгоритмов на более абстрактном уровне, чем программы на языке C++. Однако приведенные далее алгоритмы также непосредственно обобщают знакомые методы поиска, и их удобно записывать в виде С++-программ, полезных во многих ситуациях. Эта глава будет не похожа на "Специальные методы сортировки" : мы тщательно разработаем конкретные реализации, рассмотрим их основные характеристики производительности, а затем обсудим способы применения базовых алгоритмов в реальных ситуациях. Вообще-то название этой главы не совсем верно, поскольку в ней алгоритмы будут представлены в виде С++-программ, взаимозаменяемых с другими реализациями таблиц символов, которые были рассмотрены в лекциях 12—15. В таком виде они вообще не являются " внешними " методами. Тем не менее, они построены в соответствии с простой абстрактной моделью, что превращает их в подробное описание того, как можно строить методы поиска для конкретных внешних устройств.

В основном нас будут интересовать методы поиска в очень больших файлах, хранящихся на внешних устройствах наподобие дисков, которые обеспечивают быстрый доступ к произвольным блокам данных. Для устройств типа ленточных накопителей, где возможен только последовательный доступ (такая модель была рассмотрена в "Специальные методы сортировки" ), поиск вырождается до тривиального (и медленного) метода считывания от начала файла до завершения поиска. С дисковыми устройствами дело обстоит намного лучше: как ни удивительно, методы, которые мы изучим, могут поддерживать операции найти и вставить в таблицах символов, содержащих миллиарды и триллионы элементов, используя всего три-четыре обращения к блокам данных на диске. Такие системные параметры, как размер блока и отношение затрат на доступ к новому блоку к затратам на доступ к элементам внутри блока, влияют на производительность, но методы можно считать относительно не зависящими от значений этих параметров (в тех пределах, которые, скорее всего, будут встречаться на практике). А большинство важных шагов, необходимых для подгонки этих методов под конкретные реальные ситуации, достаточно просты.

Поиск — это фундаментальная операция для дисковых устройств. Как правило, файлы организованы так, чтобы можно было воспользоваться преимуществами конкретного устройства для максимально эффективного доступа к информации. Короче говоря, вполне можно предположить, что устройства, используемые для хранения очень больших объемов информации, построены именно для поддержки простых и эффективных реализаций операции найти. В этой главе мы рассмотрим алгоритмы, которые построены на несколько более высоком уровне абстракции, нежели базовые операции, обеспечиваемые дисковыми устройствами, и которые могут поддерживать операцию вставить и другие динамические операции для таблиц символов. Эти методы дают такие же преимущества по сравнению с прямыми методами поиска, как и деревья бинарного поиска и хеш-таблицы по сравнению с бинарным и последовательным поиском.

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

Массив информации, которая должна обрабатываться компьютером, называется базой данных (database). Методам построения, сопровождения и использования баз данных посвящены многочисленные исследования. Большая часть этой работы проводится в области разработки абстрактных моделей и реализаций для поддержки операций найти с более сложным критерием, чем рассмотренное простое " равенство отдельному ключу " . В базе данных поиски могут основываться на критерии частичного соответствия, который может содержать несколько ключей и возвращать большое количество элементов. Методы этого типа будут рассмотрены в частях V и VI. Запросы на поиск общего вида достаточно сложны, поэтому зачастую приходится выполнять последовательный поиск по всей базе данных, проверяя каждый элемент на соответствие критерию. И все же быстрый поиск в огромном файле крошечных фрагментов данных, удовлетворяющих заданному критерию — основная возможность в любой системе управления базами данных, и многие современные базы данных построены на основе описанных в этой главе механизмов.

Правила игры

Как и в "Специальные методы сортировки" , мы будем считать, что последовательный доступ к данным требует значительно меньших затрат, чем не последовательный. Рабочей моделью будет любое запоминающее устройство, которое можно применить для реализации таблицы символов, разбитой на страницы (page) — непрерывные блоки информации, к которым возможен эффективный доступ дисковых устройств. Каждая страница обычно содержит множество элементов, и задача заключается в организации элементов внутри страниц таким образом, чтобы к любому элементу можно было обратиться, прочитав всего нескольких страниц. Мы будем предполагать, что время ввода/вывода, требуемое для считывания страницы, значительно больше времени, требуемого для доступа к конкретным элементам или для выполнения любых других вычислений в пределах этой страницы. Во многих отношениях эта модель слишком упрощена, но она сохраняет характеристики внешних запоминающих устройств, необходимые для рассмотрения фундаментальных методов.

Определение 16.1. Страница — это непрерывный блок данных. Проба — это первое обращение к странице.

Нас интересуют реализации таблиц символов, использующие небольшое количество проб. Мы будем избегать конкретных предположений по поводу размеров страницы и отношения времени, необходимого для пробы, ко времени, которое впоследствии потребуется для доступа к элементам внутри блока. Ожидается, что эти значения должны быть порядка 100—1000; большая точность не требуется, поскольку алгоритмы не очень чувствительны к этим значениям.

Эта модель непосредственно применима, например, к файловой системе, в которой файлы состоят из блоков с уникальными идентификаторами, и назначение которой состоит в поддержке эффективных операций чтения, вставки и удаления на основе этих идентификаторов. Блок содержит определенное количество элементов, и затратами на обработку элементов внутри блока можно пренебречь по сравнению с затратами на считывание блока.

Эта модель непосредственно применима и к системе виртуальной памяти, где мы просто работаем с огромным объемом памяти и предоставляем системе самой сохранять часто используемую информацию в запоминающем устройстве с быстрым доступом (таком, как внутренняя память), а редко используемую информацию — в медленном запоминающем устройстве (таком, как диск). Многие компьютерные системы имеют сложные механизмы страничной обработки, которые реализуют виртуальную память, храня недавно использовавшиеся страницы в кэше (cash), который допускает быстрое обращение. Системы страничной организации памяти основаны на той же рассматриваемой абстракции: они делят диск на блоки и считают, что затраты на первое обращение к блоку существенно превышают затраты на доступ к данным внутри блока.

Обычно такое абстрактное представление страницы в точности соответствует блоку в файловой системе или странице в системе виртуальной памяти. Для простоты при рассмотрении алгоритмов мы всегда будем предполагать такое соответствие. В конкретных ситуациях, в зависимости от системы или приложения, блок может состоять из нескольких страниц, либо несколько блоков могут образовывать одну страницу; подобные нюансы не снижают эффективность алгоритмов, тем самым лишь подчеркивая удобство работы на абстрактном уровне.

Мы работаем со страницами, ссылками на страницы и элементами с ключами. Для большой базы данных наиболее важная для рассмотрения задача заключается в поддержке индексов данных. То есть, как было кратко упомянуто в "Таблицы символов и деревья бинарного поиска" , мы предполагаем, что элементы, образующие нашу таблицу символов, хранятся где-то отдельно, а наша задача состоит в построении структуры данных с ключами и ссылками на элементы, которая позволяет быстро получить ссылку на заданный элемент. Например, телефонная компания может хранить информацию о клиентах в огромной статической базе данных и использовать несколько индексов, возможно, использующих различные ключи, для ежемесячных оплат счетов, обработки ежедневных транзакций, периодических запросов и т.п. Для очень больших наборов данных индексы имеют первостепенное значение: обычно копии основных данных не создаются не только потому, что невозможно выделить дополнительный объем памяти, но и потому, что желательно избежать проблем, связанных с поддержкой целостности данных при использовании нескольких копий.

Соответственно, мы обычно предполагаем, что каждый элемент представляет собой ссылку на фактические данные, которая может быть адресом страницы или каким-либо более сложным интерфейсом для базы данных. Для простоты будем хранить в своих структурах данных не копии элементов, а копии ключей — часто такой подход оказывается наиболее практичным. Кроме того, для простоты описания алгоритмов мы не будем использовать абстрактный интерфейс для ссылок на элементы и страницы — вместо этого будем использовать только указатели. Таким образом мы сможем использовать наши реализации непосредственно в среде виртуальной памяти, но нам придется преобразовать ссылки и обращения к объектам в более сложные механизмы, чтобы сделать их действительно методами внешней сортировки.

Мы рассмотрим алгоритмы, которые для широкого диапазона значений двух основных параметров (размера блока и относительного времени доступа) реализуют операции найти, вставить и другие в полностью динамической таблице символов, используя для каждой операции лишь несколько проб. В типичном случае, когда выполняется огромное количество операций, может очень помочь тщательная настройка. Например, если типичные затраты на поиск удастся снизить с трех проб до двух, производительность системы может повыситься на 33%! Однако в этой главе подобная настройка не рассматривается; ее эффективность в очень большой степени зависит от используемой системы и приложения.

В первых компьютерах внешние запоминающие устройства были сложными аппаратами, которые не только были большими и медленно работающими, но и не могли хранить большие объемы информации. Поэтому было важно обойти их ограничения, и фольклор начала эпохи программирования полон историями о программах доступа к внешним файлам, которые обеспечивали прекрасную синхронизацию при чтении данных с вращающегося диска или барабана, или как-либо иначе минимизировали физические перемещения, необходимые для доступа к данным. Но фольклор полон и историями о сокрушительных провалах подобных попыток, когда малейшие просчеты существенно замедляли процесс по сравнению с простейшими реализациями. В отличие от тех монстров, современные устройства хранения информации не только очень малы по размерам и исключительно быстро работают, но и способны хранить огромные объемы информации, поэтому обычно такие проблемы решать не приходится. Вообще-то в современных средах программирования мы стремимся избегать зависимости от свойств конкретных физических устройств — чаще гораздо важнее эффективная работа программ на различных компьютерах (включая и будущие разработки), чем их максимальная производительность на конкретном устройстве.

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

Дмитрий Уколов
Дмитрий Уколов
Михаил Новопашин
Михаил Новопашин
Андрей Мураенко
Андрей Мураенко
Россия, г. Барнаул