Исходный код программы

advertisement
Оглавление
1.
Обзорная часть. Обзор методов, алгоритмов систем информационного
поиска ............................................................................................................................................................... 3
1.1. Общий обзор систем информационного поиска ............................................................ 3
1.2. Отличия от аналогов ..................................................................................................................... 5
1.3. Ожидаемые результаты ............................................................................................................... 6
1.4. Используемые методы и алгоритмы .................................................................................... 7
1.5. Области применения разработки ........................................................................................... 8
2.
Разработка методов информационного поиска на основе методов
интеллектуального анализа данных ............................................................................................... 10
2.1. Алгоритм PageRank ..................................................................................................................... 10
2.2. Алгоритм ROCK ........................................................................................................................... 16
2.3. Алгоритм плотности DBSCAN ............................................................................................. 18
2.4. Наивный байесовский классификатор .............................................................................. 21
2.5. Обзор средств лингвистического анализа ....................................................................... 25
3.
Разработка информационного и программного обеспечения системы
информационного поиска .................................................................................................................... 28
3.1. Общие сведения о разработанной информационной системе .............................. 28
3.2. Подсистема поисковых агентов ............................................................................................ 29
3.3. Подсистема сбора, анализа и хранения информации ................................................ 32
4.
Опытная эксплуатация и тестирование системы информационного поиска 35
4.1. Инструкция пользователя ........................................................................................................ 35
4.2. Пример результатов работы поисковой системы по запросу «Rammstein» с
учетом механизма PageRank ............................................................................................................... 35
1
5.
Обоснование использования библиотеки Lucene в качестве основного
поискового решения................................................................................................................................ 37
5.1. Общие сведения о библиотеке Lucene .............................................................................. 37
5.2. Аналоги библиотеки Lucene ................................................................................................... 37
5.3. Цели и преимущества использования Lucene ............................................................... 38
5.4. Дочерние проекты Lucene........................................................................................................ 39
5.5. Проекты и фирмы, использующие данное поисковое решение .......................... 40
5.6. Схема работы .................................................................................................................................. 40
5.7. Практическое использование Lucene ................................................................................. 43
5.8. Выводы............................................................................................................................................... 45
6.
Разработка методов снижения утомляемости оператора многопрофильной
системы информационного поиска ................................................................................................. 47
6.1. Общие сведения. ........................................................................................................................... 47
6.2. Общая характеристика рабочего места оператора...................................................... 48
6.3. Проблемы перегрузки зрения. Основные требования к освещению и
цветовому оформлению помещений .............................................................................................. 50
6.4. Нагрузка на костно-мышечный аппарат. Снижение физических нагрузок .. 54
6.5. Требования к микроклимату и ненормированный уровень шумов ................... 55
6.6. Специфика факторов утомляемости оператора многопрофильной системы
интеллектуального поиска ................................................................................................................... 56
6.7. Выводы............................................................................................................................................... 56
7.
Заключение. ..................................................................................................................................... 57
Использованные источники ................................................................................................................ 59
Исходный код программы ................................................................................................................... 63
2
1. Обзорная часть. Обзор методов, алгоритмов систем
информационного поиска
Общий обзор систем информационного поиска
1.1.
Количество
электронных
документов
сегодня
увеличивается
с
нарастающими темпами. Этому способствует проникновение компьютерных и
интернет-технологий в повседневную жизнь. Это стало мощнейшим стимулом
развития информационного поиска. Сегодня в мире миллионы пользователей,
огромные базы данных.
Веб-технологии открыли доступ к публикации информации миллионам
пользователей. Люди делятся фотографиями, текстами, печатают мысли в блогах
и социальных сетях, скачивают музыку, ищут приложения для мобильных
устройств, пишут отзывы на форумах и покупают бытовую технику в сети.
Соответственно именно благодаря работе с такими большими массивами данных
сделали состояние такие корпорации, как Microsoft, Amazon, Google, Twitter,
Facebook. Им приходится скачивать и просматривать терабайты и петабайты
информации для ее анализа, категоризации и выдачи пользователю. Поэтому
крупномасштабный массив информации, в котором ведется поиск, может
содержать большое количество повторяющихся символов и неочевидных и
скрытых смыслов.
Интернет стал бесконечным хранилищем информации,
поэтому традиционные хранилища не могут вместить всей необходимой
информации и продолжать работать на таком же эффективном уровне. Из-за
этого возникла необходимость упорядочить и систематизировать получаемую
информацию, проводить ее анализ. Это было бы невозможно сделать без
поисковых систем.
Работая со сложно структурированными данными, следует учитывать, что
они характеризуются:
1) внутренней интерпретацией, которая позволяет компьютеру получать
доступ
к
информации,
характеризующей
их
содержание,
модели
3
организационных единиц с процедурами анализа запроса и поиска образуют
базы данных;
2)наличием внутренней структуры связей (внутренняя иерархия, структура
связей определяется взаимосвязями между слотами внутри фрейма);
3)
наличием
внешней
структуры
связей,
которая
определяет
классифицирующие отношения быть элементом класса и содержать в себе
элементы; содержит также ассоциативные отношения;
4) шкалированием (для фиксации соотношений отдельных информационных
единиц используются метрические, оппозиционные шкалы);
5) погружением в пространство с семантической метрикой (семантическая
близость понятий внутри кластера важна для построения когнитивных систем в
памяти компьютера);
6) наличие активности: необходимо выделить предметную область, в которой
работает компьютер, а для интерпретации законов и соотношений в этой области
компьютером необходимы модели представления.
В связи с тенденцией интеграции локальных сетей с глобальными, с ростом
объемов информации сетевых ресурсов и баз данных, существенно возросла
важность проблемы релевантного поиска в источниках различного вида. Однако
применяемые в существующих системах методы не позволяют достичь высокой
полноты и точности поиска. Одной из причин является узкая специализация
систем поиска, которые не позволяют решать широкий спектр задач поиска
одновременно в нескольких информационных источниках, таких как ресурсы
глобальных и локальных вычислительных сетей, базы данных, локальные
документы на жестких дисках и т.д.
Целью данной работы является создание многопрофильной системы поиска
на основе интеллектуальных методов анализа данных, которая может получать
информацию из источников различного типа (Интернет, локальная база данных)
и обеспечивать выборку необходимой пользователю информации. Система
должна обеспечивать сбор, хранение, анализ и интерпретацию данных с учетом
синтаксиса и семантики русского языка. Система может применяться для выдачи
4
релевантных документов по неструктурированным запросам пользователей,
формирования определенных предпочтений и «подстановку» необходимых
документов под эти предпочтения. Дополнительную сложность решению задачи
придает разнообразие электронных документов: юридические акты, учебники,
неформальное общение пользователей, статьи, обзоры, рецензии и т.д. Несмотря
на то, что многие источники информации содержат неструктурированные
данные, каждый из них имеет скрытую структуру, подчиненную, как правило,
законам и правилам того языка, на котором был написан документ, что
позволяет, выделяя эту скрытую структуру, находить необходимую информацию
и понимать общий смысл документа. Это возможно с применением элементов
теории графов, средств математической статистики, линейной алгебры и теории
вероятностей.
1.2.
Отличия от аналогов
Из аналогов прежде всего стоит сказать о «Яндекс» и Google.Они
анализируют семантику документа, и когда приходит пора показывать
документы, Google старается поместить на первую страницу несколько
документов разного содержания, чтобы пользователь выбрал то, что искал.
«Яндекс» использует похожие алгоритмы. В идеале нужно сделать систему
обучаемой, чтобы, исходя из производимых запросов, можно было сказать,
какие запросы чему соответствуют.
Основные современные проблемы этих поисковых систем обусловлены
усиленной борьбой с поисковым спамом, из-за чего происходят нарушения в
индексации релевантных запросу страниц, как следствие – выдача неполных
результатов.
В настоящее время в России и за рубежом разработано несколько
промышленных систем и прототипов для поиска информации [12]. Среди
отечественных работ в этой области наиболее интересной и функциональной
является поисковая машина Russian Context Server от компании «Гарант-ПаркИнтернет». Поисковая машина Russian Context Server служит для поиска
5
текстовой информации на корпоративном узле Интернет или Интранет. Продукт
представляет собой поисковую систему, обладающую возможностями как
контекстного, так и реляционного поиска. Russian Context позволяет искать
документы с учетом морфологии русского и английского языков, используя
SQL-подобный язык запросов и комбинируя поисковые ограничения на контекст
с ограничениями на заданные атрибуты документов. Russian Context Server
использует компоненты из серии, выпускаемой компанией «Гарант-ПаркИнтернет» под маркой RCOТМ (Russian Context Optimizer).
Среди зарубежных систем можно отметить промышленную систему Convera
RetrievalWare, продукт компании Convera Technologies Corp. Продукт интересен
тем, что был локализован отечественной фирмой «Весть-МетаТехнология» и в
результате появился Русский Семантический Сервер, представляющий собой
совокупность программных средств и информационных ресурсов, позволяющих
осуществлять полнотекстовый поиск с учетом специфики русского языка. Среди
особенностей RetrievalWare можно отметить поддержку русской морфологии,
возможность поддерживать несколько семантических сетей [22]. Поиск в
локальных хранилищах и локальных сетях также актуален, потому что у любой
более-менее крупной компании есть большой документооборот, который также
необходимо каким-то образом сортировать, упорядочивать и перераспределять.
Ожидаемые результаты
1.3.
В результате работы над многопрофильной системой информационного
поиска
будет
разработано
поисковое
решение,
которое
обеспечивает
полнотекстовый поиск в документах, как расположенных на локальном
хранилище,
так
и
в
интернете.
Наивный
байесовский
классификатор
обеспечивает классификацию найденных результатов с помощью алгоритма
интеллектуального поиска с обучением. Ранжирование результатов проводится с
учетом структуры зависимостей документов PageRank.
В практической части осуществлена разработка сборщика информации,
который
поддерживает
фильтрациюURL,
таким
образом
повышается
6
релевантность. Данная система осуществляет сбор информации, ее обработку и
хранение.
Сбор информации осуществляется в глобальных и локальных сетях с
указанной глубиной обхода и максимальным количеством документов. Обходим
страницу на предмет нахождения ссылок для присвоения ранга и для
дальнейшего анализа и использования в новых модулях. Получаем множество
веб-документов, которые нам предстоит обработать. На стадии обработки с
помощью модуля синтаксического разбора получаем необходимые нам
метаданные и сам контент, который будем анализировать.
1.4.
Используемые методы и алгоритмы
Данная система реализует различные алгоритмы информационного поиска.
Среди них такие, как PageRank, наивный байесовский классификатор, DBSCAN,
ROCK и другие. Отдельно стоят алгоритмы лингвистического анализа на основе
семантических
сетей,
алгоритм
борьбы
с
опечатками.
Система
имеет
проработанную архитектуру, которая позволяет легко добавлять новые
алгоритмы и модифицировать старые.
Для данной системы информационного поиска в качестве основного
поискового решения использовалась библиотека Lucene, которая дает хорошие
результаты по поиску. Она обеспечивает полнотекстовый поиск, поддержку
лемматизации и русской морфологии. Благодаря поисковому решению
Luceneстроятся индексы, в которых затем производятся поиск и оценка
релевантности.
Для анализа текстов и их категоризации к релевантным документам
используется алгоритм наивного байесовского классификатора, который
обеспечивает хорошие результаты и классификацию документов на большой
выборке разнородных данных. Алгоритм PageRank позволяет производить
ранжирование документов, основываясь на их структурных взаимосвязях. Имея
набор заданных классов, необходимо определить, к какому из них принадлежит
заданный объект. Цель классификации текстов – обеспечить высокую точность
7
новых данных на основании тех, которые у нас уже имеются. Наивный
байесовский классификатор является статистическим классификатором, поэтому
необходимо многократно проходить этапы тестирования и обучения. Во время
эксплуатации классификатор применяется на тех данных, классификацию
которых мы хотим получить.
Основной
используемый
алгоритм
лингвистического
анализа
–
семантические сети, информационная модель предметной области, имеющая вид
ориентированного
графа,
вершины
которого
соответствуют
объектам
предметной области, а дуги задают отношения между ними[8].То есть элементы
предметной области соотносятся друг с другом разными типами связей:
количественными, пространственными, временными, логическими и прочее.
Каждое слово имеет
множество устойчивых связей. Исходя из общности
встречаемых с ним слов и определяется значение исходного слова. Основное
преимущество семантических сетей в том, что вся точно известная информация
о том или ином предмете расположена в круге соответствующей вершины.
Информация при этом организуется в четкую и ясную схему.
Алгоритм борьбы с опечатками в середине слова позволяет исправлять
опечатки в поисковых запросах, в тексте. Он действует на основе анализа длины
слова.
1.5.
Области применения разработки
Применение системы интеллектуального поиска возможно во многих
областях, в первую очередь при поиске информации (в том числе в социальных
сетях). Сюда же можно отнести и различные механизмы рекомендаций для
социальных сетей.
Широкая сфера применения - установление авторства и проверка на плагиат.
Это актуально при защите авторского права и речеведческой экспертизе в
судебных делах.
8
Еще одна область - автоматическая генерация текстов, которая применима в
SEO-оптимизации (оптимизация поисковых запросов), копирайтинге (написание
рекламных текстов)- областях, нуждающихся в уникальном контенте.
Следующая сфера – лингвистический анализ текста, к примеру, анализ и
сравнение исторических и литературных памятников, языковых стилей,
лексиконов, анализ в школе на уроке и т.п. Использование системы
интеллектуального поиска поможет затрачивать меньше усилий, точнее
выполнять анализ при больших его объемах, применять новые методы
интерпретации текста.
Интересной была бы функция корректировки текстов и помощь в
подходящем выражении мысли, в поиске ее формы. Это возможно через подбор
синонимов, исправление сложных или неясных синтаксических конструкций и
подобное.
Также система позволит сэкономить и оптимизировать данные для
эффективного использования БД и память для увеличения быстродействия.
9
2. Разработка методов информационного поиска на
основе методов интеллектуального анализа данных
2.1.
Алгоритм PageRank
Для любой системы информационного поиска необходимо использовать
методы и алгоритмы, которые позволят называться ей эффективной.
Ранг (PageRank) рассчитывается для каждой страницы по довольно простой
формуле[14]:
PageRank{A) := (1-d) + d(PageRank(T1)+...+PageRank(Tn) )
C(T1)
C(Tn)
Коэффициент d — это коэффициент дампинга, обычно равен 0,85 (может
быть в пределах 0— 1). Он отвечает за то, чтобы при перемещении со страницы
на страницу мы строго следовали структуре веб-страницы, а вероятность
перехода на другую страницу, не связанную с данной равна 100%-85%=25%
Элемент С (Ti) — это количество исходящих ссылок. Как видно, ранг вебстраницы вычисляется как сумма рангов всех страниц, которые указывают на
нашу страницу (т.е. являются входящими ссылками), которая в свою очередь
разделена на число исходящих ссылок для каждой страницы.
Исходя из этой формулы, на ранг страницы могут существенно повлиять два
фактора:
■ количество входящих ссылок;
■ количество исходящих ссылок.
Приведем пример расчета.
Введем понятие веса веб-страницы. Вес страницы – это мера значимости
страницы относительно других страниц; и страница может разделить свой вес
между одной, двумя или многими ссылками, но сумма всех оценок будет всегда
той же самой.
10
Вес PageRank, передаваемый на страницу A со страницы B (см. рис 2.1.1),
которая указывает на нее, уменьшается с каждой ссылкой куда-нибудь, которая
находится на странице B [24].
Рис 2.1.1Схема работы алгоритма PageRank
Вначале
неизвестно,
какие
веса
PageRank
у
этих
страниц,
они
присвоены.Действует правило передачи веса. Вначале применяем коэффициент
затухания (страница не может голосовать так, чтобы другая страница была столь
же важна, как она сама, следовательно, страницы, к которым труднее добраться в
Web, менее важны) Затем делим сохранившийся вес на число ссылок.
Подсчитываем итоговый вес, который должен быть добавлен ко всем страницам,
перед тем как окончательно его прибавим.
Итак, глядя вначале на страницу A, видим, что значение веса PageRank,
доступное для передачи, после затухания равно 1 * 0,85= 0,85. Со страницы
ведут две ссылки, поэтому по окончании итерации, добавим 0,425 к весу
PageRank страницы B и 0,425 к весу PageRank страницы C. Нельзя сделать этого
до тех пор, пока не рассчитаны все ссылки страницы, потому что это влияет на
результаты.
Страница B содержит только одну ссылку, поэтому она передаст 1 * 0,85 =
0,85 странице C, когда будут окончены все вычисления для ссылок.
11
Страница C также имеет одну ссылку. Поэтому она передаст вес 1 * 0,85 =
0,85 странице A. Страница D имеет одну ссылку, поэтому она передает 0,85
странице C.
Сейчас можно добавить все суммы к весам страниц. См. рис 2.1.2.
Рис 2.1.2Схема работы алгоритма PageRank. 1 итерация
Новые значения весов PageRank показывают, сколь важна страница C. Но
поскольку все страницы начали с одного значения, вычислена только
популярность в ссылках (link popularity). Суть PageRank такова, что страницам,
на которые чаще ссылаются, следует получить более высокую оценку; поэтому
нужно проделать то же еще раз. На этот раз страница C имеет большее влияние,
потому что ее текущий вес PageRank выше.
Рассмотрим страницуA. Ее текущий вес MiniRank равен 1,85. Величина
MiniRank, доступная для передачи, после применения затухания составляет 1,85
* 0,85 = 1,5725. Есть две ссылки со страницы, поэтому по завершению итерации
мы добавим 0,78625 к весу PageRank страницыB и весу PageRank страницыC.
Перейдем к странице B. У нее есть только одна ссылка. Следовательно, она
передаст 1,425* 0,85= 1,21125 страницеC, когда мы завершим все вычисления со
ссылками.
СтраницаC также имеет одну ссылку, но при этом обладает огромным весом
3,125 PageRank. Поэтому она передаст 3,125* 0,85 = 2,65625 странице A.
12
СтраницаD имеет одну ссылку, поэтому она передает 0,85 страницеC.См
рис.2.1.3.
Получаем:
Рис. 2.1.3 Схема работы алгоритма PageRank 2 итерация
Уже можно видеть, что страницаC имеет наибольший вес PageRank,
страницаA— следующий по величине. На практике нам нужно повторить эти
действия от 50до 100раз, чтобы гарантировать, что низкая точность предыдущих
итераций сведена к минимуму.
Во время одной итерации вычислений страницаC дает страницеA повышение
в весе PageRank. Во время следующей итерации она сама получает увеличение
веса, пропорциональное новому улучшившемуся весу PageRank страницыA (она
получает назад часть своего веса PageRank).Фактически, она нужна для
правильного функционирования PageRank и является частью алгоритма.
Во время перехода пользователя по ссылкам можно встретить страницу,
которая не содержит ссылок. Такая страница называется «висячим узлом». Это
приводит к тому, что невозможно вычислить дальнейшее влияние взаимного
расположения веб-страниц, и делает алгоритм PageRank менее эффективным.
Когда пользователь, переходящий по ссылкам во всемирной сети, добрался до
висячего узла и не нашел ни одной ссылки на другую страницу, то он должен
ввести другую случайную URL для перехода. Это соответствует замене в
матрице гиперссылок всех нулевых значений на 1/n, где n– количество строк в
13
матрице или количество страниц, которое мы рассматриваем. Такая коррекция
носит название стохастической поправки.
Кроме того, пользователь может перескочить на другую страницу, не следуя
структуре связей веб-страниц. Чтобы учесть произвольные скачки, вводится
новый параметр alpha, или коэффициент затухания. Он определяет время, в
течение которого пользователь будет перемещаться по страницам, при этом он
будет следовать по ссылкам, а не перескакивать произвольно с одной страницы
на другую. Такая коррекция матрицы называется поправкой примитивности.
Параметр alpha уменьшает влияние тех веб-страниц, до которых сложнее
добраться.
Затем текущее значение сравнивается со значением, полученным на
предыдущей итерации и процесс повторяется до тех пор, пока не будет получена
необходимая точность зависящая от заданной epsilon (величина допустимой
погрешности между итерациями). Этот параметр называют порогом сходимости
векторов PageRank. Таким образом, алгоритмы ранжирования ориентируются в
первую очередь относительные веса друг друга, что и позволяет производить
ранжирование. То есть из ссылочной структуры веб-страниц выносим их
релевантность, которая не зависит от запросов пользователей. Поэтому алгоритм
PageRank применяется в основном со множеством других факторов оценки
релевантности страницы.
Действие алгоритма схематически представлено на Рис. 2.1.4.
14
Рис. 2.1.4. Схема алгоритма PageRank
15
2.2.
Алгоритм ROCK
Данный алгоритм предназначен для кластеризации, т.е. для формирования
групп на основе исходных данных. Он является агломеративно-иерархическим,
так как начинает с отдельных элементов и формирует кластеры, объединяя их с
другими элементами по направлению к глобальному суперкластеру [28].
Огромные массивы информации в интернете способствуют тому, что
необходимо выделять определенные тематические группы, в которых человеку
было бы легче ориентироваться. Тогда пользователь смог бы исключить те
группы, которые не являются релевантными для него и продолжить поиск в
интересующих группах.
Основная идея алгоритма заключается в том, чтобы использовать связи
между терминами как меру сходства. Целью данного алгоритма является
объединение в одном кластере точек, имеющих много общих связей.
В качестве исходных данных обычно используют точки данных (термины,
представленные в виде точек для их математической интерпретации). Каждая
точка находится в собственном кластере, затем продолжается объединение до
тех пор, пока все точки не будут принадлежать единственному кластеру,
Поэтому необходимо задать количество полученных кластеров, чтобы знать,
когда прекратить объединение, чтобы не получить один большой кластер. Затем
следует указать параметр, который позволит определить степень близости между
двумя точками, чтобы сформировать связь между точками. Одного критерия
максимизации связей для определения кластера недостаточно, так как
максимальное количество связей возможно и в одном кластере. Поэтому следует
ввести еще один критерий: оценить суммарное число связей одного кластера и
оценить суммарное числосвязей другого кластера.
1−𝑎
Каждая точка, принадлежащая первому кластеру, имеет𝑛1+𝑎 , где n –
количество точек внутри кластера, a – число кластеров, которое нужно
сформировать. Таким образом, при соблюдении вышеназванных двух критериев
16
можно, во-первых, сформировать кластеры, во-вторых, не допустить включения
в кластер лишних точек.
Представляется алгоритм следующим образом [10]:
Procedurecluster (S, k)
Begin
1. link := compute-links (S)//ВычисляемсвязивмножестветочекS
2. for each s from S do
3. q[s] := build-local-heap (link,S)//ИзкаждойточкимножестваS на основе
связей формируем кластер
4. Q:=build-global-heap (S,q) //Содержит список всех кластеров множества S
5. whilesize (Q) >kdo {//Формируем кластеры, точки, которых имеют
максимальное число связей до тех пор, пока не получим желаемое число
кластеров
6. u := extract-max (Q)
7. v := max (q[u])
8. delete (Q,v)
9. w:= merge (u,v)
10. for each x from (q[u] or q[v]) do {
11. link [x,w] := link [x,u] + link [x,v]
12. delete (q[x],u); delete (q[x],v)
13. insert (q[x],w,g(x,w)); insert (q[w],x,g(x,w));
14. update (Q,x,q[x])
15. }
16. insert (Q,w,q[w])//Добавляем кластер в список всех кластеров
17. deallocate (q[u]); deallocate (q[v]);
18. }
end.
Этот алгоритм берёт в качестве входных параметров множество S изnпробных точек для кластеризации, и k - количество требуемых кластеров.
Сначала считается количество ссылок между парами точек. Изначально, каждая
17
точка - отдельный кластер.Q – множество всех кластеров. Затем объединяем
кластеры по наибольшему числу связей. Когда находится подходящий кластер
для точки, удаляем ее из множества Q, и она соединяется с другим кластером.
Подсчетсвязей:
Procedurecompute-links (S)
Begin
1.
Computenbrlist
[I]
foreverypointiinS//Вычисляемсвязимеждуточкаминаосновематрицысмежности
2. Setlink [i,j] to be zero for all i,j
3. for i:=1 to n do {
4. N:= nbrlist[I]
5. for j:=1 to |N| -1 do
6. for l:= j+1 to |N| do
7. link[N[j], N[l]] := link [N[j],N[l]]+1
8. }
end.
2.3.
Алгоритм плотности DBSCAN
DBSCAN представляет термины как точки в n-мерном пространстве. Близкие
термины он объединяет в группы. Чем больше терминов располагается ближе
друг к другу, тем больше вероятности, то они расположены в одном кластере
[28]. Важна здесь плотность расположения кластеров с точками, которые лежат
рядом с кластером, но к нему могут не относиться. Границы объектов
определяются на основе градиентов плотности.
Воттаквыглядитсам алгоритм:
public List<Cluster> cluster() {
int clusterId = getNextClusterId();
for(DataPointp : points) {
if(isUnclassified(p) ) {//Проверяем классифицировали ли мы данную точку.
18
boolean
isClusterCreated
=
createCluster(p,
clusterId);
//Создаемкластердлякаждойточки
if( isClusterCreated ) {
clusterId = getNextClusterId();
}
}
}
List<Cluster> allClusters = new ArrayList<Cluster>();
for(Map.Entry<Integer, Set<DataPoint>> e : clusters.entrySet()) {
String label = String.valueOf(e.getKey());//Создаемкластериимядлянего
Set<DataPoint> points = e.getValue();
if( points != null && !points.isEmpty() ) {
Cluster cluster = new Cluster(label, e.getValue());
allClusters.add(cluster);
}
}
returnallClusters;//Возвращаемсписоквсехкластеров, которыебылисозданы
}
private
boolean
createCluster(DataPoint
p,
Integer
clusterId)
{//Создаемкластернаосноведанныхоточкеиid кластера
boolean isClusterCreated = false;
Set<DataPoint> nPoints = findNeighbors(p, eps);
if( nPoints.size() < minPoints ) {
assignPointToCluster(p,
CLUSTER_ID_NOISE);//Есликоличествоточекокружностименьше, чемminPoints,
присваиваемточкезначение «Шум»
isClusterCreated = false;
} else {
assignPointToCluster(nPoints, clusterId); //Иначедобавляемточкувкластер
nPoints.remove(p);//Удаляем точку из рассмотрения
19
while(nPoints.size() > 0 ) { //Просматриваем все точки, если нашли точку,
которую уже рассматривали то ставим ей статус пограничной, добавляем в
кластер и удаляем из рассмотрения
DataPoint nPoint = nPoints.iterator().next();
Set<DataPoint> nnPoints = findNeighbors(nPoint, eps);
if( nnPoints.size() >= minPoints ) {
for(DataPoint nnPoint : nnPoints ) {
if( isNoise(nnPoint) ) {
assignPointToCluster(nnPoint, clusterId); //Добавляемточкуккластеру
} else if( isUnclassified(nnPoint) ){
nPoints.add(nnPoint);
assignPointToCluster(nnPoint, clusterId);
}
}
}
nPoints.remove(nPoint); //Удаляемточкуизрассмотрения
}
isClusterCreated = true;
}
return isClusterCreated;
}
Идеяалгоритмавтом,
чтомыокружаемкаждуюточкуокружностьюсвеличинойрасстояния
epsilon.
Все
точки,
которые
лежат
внутри
окружности,
(радиусом)
называются
окруженными, а статус тех, которые принадлежат данному кластеру, но не
окружены, остается неизвестным. За шум принимаем все точки, что не относятся
ни к одной окружности.
Далее смотрим на величину minPoint (константа), которая отвечает за
минимальное количество точек внутри кластера. Если ее значение больше, то
удаляем точки до тех пор, пока их количество не будет равно minPoint.
20
Перебираем все точки и находим epsilon (радиус окружности, которая
охватывает точки) их окрестности. Если текущая точка является плотно
достижимой, то эта точка принадлежит кластеру. Если же у точки статус
неопределенный и эта точка достижима из окружностей других точек, которые
принадлежат этому кластеру, то эта точка является пограничной. Если же она не
принадлежит окружности, то является шумом (рис. 2.3.1.).
Рис 2.3.1 Схема принципа работы алгоритма DBSCAN
Если вокруг точки больше или равно minPoint, значит, точка является
центром
epsilon-окружности.
Если
внутри
этой
окружности
находится
рассмотренная пограничная точка, значит, она принадлежит кластеру.
Итак, основная суть алгоритма заключается в том, что мы последовательно
перебираем все точки, строим вокруг них epsilon-окружности, помечаем точки
статусом «неопределенная», пограничная или шум. Статус точки зависит от
следующих итераций.
2.4.
Наивный байесовский классификатор
Для того чтобы описать степень общности запросов и контента, необходимо
проводить такую операцию, как классификация. Имея набор заданных классов,
необходимо определить, к какому из них принадлежит заданный объект. Цель
классификации текстов – обеспечить высокую точность новых данных на
основании тех, которые у нас уже имеются. Такой вид обучения называется
обучения с учителем, так как классы обучающего множества задаются
пользователем (учителем) [28].
Вычисляется вероятность причисления к классам по формуле:
21
– вероятность наблюдения концепта Х в общем случае, или априорная
вероятность.
- вероятность наблюдения образца Y при условии, что мы случайным
образом выбираем образец из концепта Х, или правдоподобие.
– вероятность наблюдения образца Y в общем случае, также называемая
подтверждением.
На выходе классификатора
– вычисленная вероятность того, что
образец Yпринадлежит концепту X или апостериорная вероятность. Когда мы
занимаемся классификацией то оценка подтверждения p(Y) не требуется, т.к. это
значение не меняется для разных классов. После вычисления апостериорных
вероятностей для всех классов мы выбираем класс с наибольшей апостериорной
вероятностью. Так как сам порядок величины не изменяется, то можно
пренебречь данным параметром, чтобы выполнять меньшее количество
вычислений.
Теперь рассмотрим жизненный цикл классификатора (рис. 2.2.1). На этапе
обучения
классификатору
предоставляются
обучающие
наборы
данных,
которым уже назначен соответствующий класс. Классификатор содержит
несколько атрибутов, которые определяются перед использованием. Далее
следует этап тестирования, на котором проверяется корректность работы
классификатора. Данные, используемые на этапе тестирования, должны
отличаться от использованных на этапе обучения. Наивный байесовский
классификатор является статистическим классификатором, поэтому необходимо
многократно проходить этапы тестирования и обучения. Во время эксплуатации
классификатор применяется на тех данных, классификацию которых мы хотим
получить. Далее эти три шага повторяются каждый раз, для того, чтобы
достигнуть наилучших результатов обучения классификатора и результатов
эксплуатации.
Наивным данный алгоритм называется потому, что атрибуты (независимые
друг от друга объекты) предполагаются статистически независимыми. Поэтому
22
мы оцениваем правдоподобие наблюдаемого образца как произведение
вероятностей наблюдения каждого из значений атрибутов.
23
Рис. 2.2.1. Жизненный цикл наивного байесовского классификатора
24
2.5. Обзор средств лингвистического анализа
Задача, стоявшая перед разработчиками поисковых систем, заключается в
том, чтобы позволить пользователю вычленить во множестве документов
(текстов) только те, что отвечают набору критериев релевантности, задаваемых
искомой информацией. Основные проблемы в этой области связана с
асимметрией языкового знака, которая проявляется в случаях выражения одного
значения разными формами (синонимия) и выражения одной формой разных
значений (полисемия, омонимия). Кроме того, не все поисковые системы
работают с формами одного и того же слова и супплетивными формами, что
усложняет проблему. Вкупе все это снижает показатели точности и полноты
поиска.
Среди актуальных проблем информационного поиска назовем: анализ слов с
дефисами [27] (co-education, Hewlett-Packard). В примере с дефисами первое
слово нужно рассматривать как одну лексему (т.к. чаще пишется слитно),
последнее следует разделить на несколько слов. При сложных случаях можно
рассматривать
это
как
задачу
классификации
либо
применять
некие
эвристические правила, например допускать в терминах только короткие
префиксы. Разделение лексем пробелами (LosAngeles) может привести к
неправильным результатам. Сюда же относятся телефонные номера, даты.
Нужно, чтобы запросы на поиск слов lowercase, lowercaseиlower-case приводили
к одинаковым результатам.
Каждый новый язык порождает новые проблемы. Так, трактовка документа
как нелинейной последовательности символов часто оказывается неадекватной в
некоторых системах письменности[6], например в арабских языках, в которых
текст является двумерным и не имеет строгого порядка следования символов. Но
несмотря на это, тексту соответствует последовательность звуков и, таким
образом, сохраняется линейная структура. В немецком языке сложные слова
записываются
слитно:
Computerlinguistik
(компьютерная
лингвистика),
Lebensversicherungsgesellschaftsangestellter (сотрудник общества по страхованию
жизни). Чтобы повысить эффективность работы поисковых систем для
25
немецкого языка, используется модуль, разбивающий сложные слова на
несколько
составных
частей.
Наиболее
ярко
эффект
проявляется
в
восточноазиатских языках: в них вообще нет пробелов.
По грамматическим причинам в документах встречаются разные формы
одних и тех же слов, например organize, organizes, organizing. Кроме того,
существует семейства производных слов, имеющих близкий смысл, например
democracy, democratic, democratization. Цель стемминга и лемматизации–
привести словоформы и производные формы слова к общей основной форме
[27]. Стеммингом называется приближенный эвристический процесс, в ходе
которого от слов отбрасываются окончания в расчете на то, что в большинстве
случаев это себя оправдает. Лемматизация – точный процесс с использованием
лексикона и морфологического анализа слов, в результате которого удаляются
только флективные окончания и возвращается основная, или словарная, форма
слова, называемая леммой. Существуют различные алгоритмы стемминга и
лемматизации.
Для создания поисковой системы необходим тезаурус. Он создается вручную
или автоматически (путем анализа коллекции документов) 1) с помощью
совместной
встречаемости
грамматического
анализа
слов,
2)
текста,
с
использованием
грамматических
поверхностного
зависимостей
и
отношений).Основными целями разработки тезауруса являются следующие [1]:
 обеспечение
перевода
пользователей
на
естественного
контролируемый
языка
словарь,
документов
применяемый
и
для
индексирования и поиска;
 обеспечение
последовательного
использования
единиц
индексирования;
 описание отношений между терминами;
 использование как поискового средства при поиске документов.
Каждому ресурсу при классификации могут быть сопоставлены одно или
более понятий, описываемых
терминами
в тезаурусе, а пользователь,
осуществляющий поиск, может по тезаурусу найти интересующие его понятия в
26
данной предметной области, а также все характеризующие их термины [30]. То
есть на основе связей тезауруса происходит расширение поискового запроса
(расширение слов запроса синонимичными, более общими или более частными
по смыслу терминами). Навигация по связям тезауруса помогает четче
сформулировать сам запрос.
Опишем действие алгоритма борьбы с опечатками в середине слова. Если
слово является одно- или двухбуквенным, оно не анализируется. Если слово
является четырехбуквенным, анализируются первая и последняя буквы. Если в
слове 6 букв – анализируются две первые и последняя, 8 букв – 3 первые и
последняя, и так далее по мере возрастания длины слова. Также следует
учитывать множество вариантов окончаний слова. Данный вид поиска позволяет
производить уточнение, повышая релевантность документов засчет уменьшения
точности поиска. Допустим, на входе есть слово, которое ищет пользователь.
Анализируются первая и последняя буквы слова, затем они сравниваются с
первыми и последними буквами слов, содержащихся в тексте. Если было
обнаружено совпадение, то ведется анализ следующей первой и следующей
последней буквы. При этом приоритет отдается первым буквам и согласным, так
как буквы, стоящие в начале слов, менее подвержены изменениям, чем буквы в
конце. Согласные же – главная опора слова, по ним слово можно распознать.
27
3.Разработка
информационного
и
программного
обеспечения системы информационного поиска
3.1.
Общие сведения о разработанной информационной
системе
Для разработки информационной системы необходимо реализовать два
главных функциональных модуля. 1) подсистема поисковых агентов, 2)
подсистема сбора, анализа и хранения. Подсистема поисковых агентов
представляет собой совокупность программных модулей, которые необходимы
для успешного сбора и обработки информации. Она осуществляет сбор и
предоставление необходимой информации для подсистемы сбора и анализа
информации.
Подсистема
сбора
и
анализа
обеспечивает
обработку
пользовательских запросов, прием и хранение информации от поисковых
агентов, производит оценку релевантности между запросами и индексированным
контентом с использованием методов интеллектуального анализа данных.
Структурная схема программы приведена на рисунке 3.1.1.
28
Рис. 3.1.1. Структурная схема многопрофильной системы
информационного поиска
3.2.
Подсистема поисковых агентов
Подсистема поисковых агентов представляет собой сборщик информации,
который начинает обход веб-страниц с указанной страницы. Данная подсистема
имеет следующие компоненты:
 Модуль хранения и обслуживание известных ссылок на другие
документы.
 Модуль загрузки новых документов, который обеспечивает извлечение
документов по предоставленному набору URL.
29
 Модуль
синтаксического
разбора
документов,
отвечающий
за
извлечение текста из html,pdf,doc. Также в задачу модуля входит
извлечение URL-адресов на другие страницы и получение метаданных,
таких как кодировка документа и его тип.
 Модуль
хранения
метаданных
и
контента,
извлеченных
из
загруженных документов.
 Модуль
нормализации
то
URL-адреса,
есть
преобразование
относительных путей в абсолютные.
 Модуль фильтрации URL. Его задача – отсеивать ненужные или
нежелательные для посещенияURL.
Жизненный цикл подсистемы поисковых агентов выглядит следующим
образом:
1) Поисковый робот инициализируется списком URL адресов и начинает
сбор информации по данным URL адресам.
2) Для каждого URL робот получает информацию, которая доступна по
адресу.
3) Выполняет
синтаксический
разбор
документа,
чтобы
получить
исходящие URL и содержимое документа.
4) Нормализуем обнаруженные URL в соответствии с видом, который
позволит использовать их при дальнейшем сборе информации
(например, при переводе относительных пути к абсолютным).
5) Отфильтровываем URL, которые робот должен игнорировать.
6) Обновляем хранилище URL, внося список новых адресов, полученных
в результате сбора информации.
7) Повторяем шаг 2 до тех пор, пока не достигнем нужной глубины
поиска или нужно количества документов.
Схема используемой для хранения документов базы данных приведена на
рис.3.2.1.
30
31
Рис. 3.2.1. Используемая для хранения документов база данных
Остановимся на структуре робота более подробно.
Каждый раз запуске сборщика данных из информационных массивов,
создается новый каталог crawl-<timestamp>. Внутри него имеется следующая
структура каталогов и файлов(Рис 3.2.1):
<crawl-dir>/knownurls/knownurlsdb.datфайл содержит список известныхURL.
<crawl-dir>/gathered – здесь хранятся оригинальные документы, которые не
подверглись обработке.
<crawl-dir>/gathered
-
<batch-number>/<docId>.fetched–
экземплярисходногодокумента.
<crawl-dir>/gathered-<batch-number>/<docId>.meta
–
содержит
мета
информацию о каждом документе, такие как кодировка, URL, тип.
<crawl-dir>/processed/ - в этом каталоге хранятся обработанные документы.
<crawl-dir>/processed/<batch-number>/content/<doc-id>.content
–
содержит
контент, полученный после синтаксического разбора.
<crawl-dir>/processed/<batch-number>/<doc-id>.outlinks – содержит внешние
ссылки, обнаруженные модулем синтаксического разбора документов.
–
<crawl-dir>/processed/<batch-number>/properties<doc-id>.properties
вданномфайлехранитсятипдокумента, заголовок, URL.
<crawl-dir>/processed/<batch-number>/txt/<doc-id>.txt – содержиттолькотекст,
извлеченныйсинтаксическим разборомиздокумента.
<crawl-dir>/pagelinks/ pagelinksdb.dat – здесь хранятся данные о внешних
ссылках для всех обработанных URL.
3.3.
Подсистема сбора, анализа и хранения информации
Подсистема сбора, анализа и хранения состоит из трех главных компонентов:
 Система полнотекстового поиска Lucene.
 Система, реализующая алгоритм ранжирования документов PageRank.
 Система, реализующая алгоритм классификации - наивный Байес.
После того, как подсистема поисковых агентов закончила работу, начинает
свою работу подсистема сбора, анализа и хранения информации.
32
Теперь разберем на конкретном примере работу индексатора.
После
того,
как
сбор
информации
поисковым
роботом
завершен,
обработанные данные подаются на вход LuceneIndexBuilder с указанием папки, в
которой следует хранить индексы.
Формируем документ, который будет храниться в индексе, с помощью
создания нового объекта Document.
После его создания сохраняем его при помощи объекта IndexWriter, который
сериализует (сохраняет состояние объекта в последовательность байт) объект
Document и сохраняет его в указанной директории.
Программный код можно видеть ниже:
try {
List<String>docIdList = parsedDocsService.getDocumentIds(groupId);
IndexWriterindexWriter = newIndexWriter(indexDir, new StandardAnalyzer(),
false);//Создаемобъект, которыйбудетзаписыватьиндексывдиректориюindexDir
for(String docId : docIdList) {
indexDocument(indexWriter, parsedDocsService.loadDocument(docId));
}//Формируем индекс на основе загруженных документов и сохраняем его
indexWriter.close();//Закрываем поток объект IndexWriter
}
catch(IOException ioX) {
throw new RuntimeException("Error while creating lucene index: ", ioX);
}
После того, как индексатор закончил работу, система ждет, когда
пользователь введет свой запрос, чтобы начать поиск по индексам. Lucene
создает очередь запроса Query нужного типа, затем производит ее анализ и
создает новый объект searchDocument, поля которого он сравнивает с
storeDocument, который формируется на основе сохраненных индексов. Далее,
если поле представляет собой большой объем текста, то он сортируется по
алфавиту,
и
производится
двоичный
поиск
с
ключом,
взятым
из
33
соответствующего поля searchDocument. Стоит также отметить, что во время
поиска Lucene формирует собственные результаты ранжирования документов,
которые затем можно использовать при помощи вызова функции getScore. Далее
с помощью алгоритма PageRank вычисляется релевантность с учетом критерия
взаимосвязности страниц. При учете данной оценки необходимо искусственно
понизить ее, чтобы маленькое количество документов не давало высокую
релевантность. Производится оценка релевантности при помощи класса
NaiveBayes, которая определяет насколько тот или иной документ относится к
заданному поисковому вопросу. Затем результаты ранжирования Lucene, оценки
наивного
байесовского
классификатора
и
PageRank
перемножаются,
и
документы сортируются в порядке убывания величины релевантности.
34
4.Опытная эксплуатация и тестирование системы
информационного поиска
Инструкция пользователя
4.1.
Для того чтобы использовать система многопрофильного поиска необходимо
запустить сервер приложений ApacheTomcat 6.0 или выше. Для этого нужно
скачать дистрибутив ApacheTomcat по адресу: http://tomcat.apache.org/download60.cgi . Далее следует скопировать папку с веб-приложением в папку webapps и
запустить Tomcat с помощю %TOMCAT_HOME%/bin/startup.bat
В адресной строке браузера набрать localhost:8080. Если появится
приветственная страница ApacheTomcat, то сервер приложений работает
корректно. Затем необходимо ввести в адресной строке адрес нашего
приложения localhost:8080/MGSearcher, и откроется страница поисковика (рис.
4.1.1.).
Рис. 4.1.1Скриншот главной страницы программы.
Вводим имя пользователя и поисковый запрос, затем нажимаем «поиск».
Поисковик выводит результаты в соответствии с механизмами ранжирования.
4.2.
Пример результатов работы поисковой системы по
запросу «Rammstein»с учетом механизма PageRank
В
качестве
отправной
страницы
выбранаWikipedia.
Задали
запрос
«Rammstein» с глубиной обхода 2 и максимальным количеством документов 200.
Система поиска выдает 6 страниц. Рядом с каждым адресом указан вес
страницы.
PageURL:
http://ru.wikipedia.org/wiki/%D0%92%D0%B8%D0%BA%D0%B8%D0%BF%D0%
35
B5%D0%B4%D0%B8%D1%8F:%D0%98%D0%B7%D0%B1%D1%80%D0%B0%
D0%BD%D0%BD%D1%8B%D0%B5_%D1%81%D1%82%D0%B0%D1%82%D1
%8C%D0%B8 --> Rank: 0,088311989074287
Page
URL:
http://ru.wikipedia.org/wiki/%D0%92%D0%B8%D0%BA%D0%B8%D0%BF%D0%
B5%D0%B4%D0%B8%D1%8F:%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%
D0%BD%D0%B8%D0%B5 --> Rank: 0,088311989040776
Page
URL:
http://ru.wikipedia.org/wiki/%D0%92%D0%B8%D0%BA%D0%B8%D0%BF%D0%
B5%D0%B4%D0%B8%D1%8F:%D0%A1%D0%BF%D1%80%D0%B0%D0%B2%
D0%BA%D0%B0 --> Rank: 0,088311989006108
Page
URL:
http://ru.wikipedia.org/wiki/%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%
B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%
D0%B8%D1%86%D0%B0 --> Rank: 0,088311988973977
Page
URL:
http://ru.wikipedia.org/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%
B1%D0%BD%D0%B0%D1%8F:%D0%9D%D0%BE%D0%B2%D1%8B%D0%B5_
%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D1%8B
-->
Rank: 0,052993511385629
Page
URL:
http://ru.wikipedia.org/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%
B1%D0%BD%D0%B0%D1%8F:%D0%A1%D0%B2%D0%B5%D0%B6%D0%B8%
D0%B5_%D0%BF%D1%80%D0%B0%D0%B2%D0%BA%D0%B8
-->
Rank:
0,052993511384367
36
5.Обоснование использования библиотекиLucene в
качестве основного поискового решения
5.1.
Общие сведения о библиотеке Lucene
Реализация хорошего поиска – это сложная задача. Поиск часто является
слабым местом многих приложений, особенно Web-приложений. Поэтому в
качестве опорной технологии для написания дипломной работывыбрана
библиотека полнотекстового поиска Lucene[15]. Эта библиотека полностью
написана на языке Java. Данная технология применима практически для любого
приложения,
которое
требует
полнотекстового
поиска
поразного
рода
документам. Данная библиотека лицензирована под Apache License, Version
2.0[19], что позволяет ей распространяться свободно и с открытым исходным
кодом. Одним из главных плюсов является поддержка со стороны Apache
Software Foundation[18], сообщества, члены которого давно зарекомендовали
себя как высококвалифицированные профессионалы.
5.2.
Аналоги библиотеки Lucene
Основным конкурентом библиотеки Lucene является библиотека Sphinx[17].
Она написана на языке С++ и является кроссплатформенной. Поддерживает
следующие языки: РНР, Ruby, Python, Java, Perl, С++. Распространяется по
лицензии GPL2 [13]. Обладает высокой скоростью работы и индексации.
Поддерживается распределенный поиск и кластеризация. Однако для работы
требуется выделенный поисковый сервер. Данное решение хорошо подходит для
крупных и средних проектов,однако малоприменимо для маленьких.
Apache Lucene позволяет встраивать код в разные виды приложений от
настольных до веб-серверных, поэтому данное решение имеет более широкий
охват проектов. Также Apache Lucene имеет порты к другим языкам, таким как:
C++, Perl, Java, .NET, Ruby, Python, PHP.
37
Среди аналогов стоит отметить библиотеку XAPIAN[9]. Она может
использоваться исключительно как встраиваемая библиотека. В отличие от
Lucene и Spinx, она строит индекс, который не требует полной перестройки при
добавлении нового документа. Имеет большое количество портов: С++, Perl API,
Java JINI, Python, PHP, TCL, C# и Ruby. Однако у нее довольно бедная
документация. Поддержка Xapian в качестве поискового сервера является
слабой.
Свое поисковое решение предлагает компания Яндекс[11]. Ее сервер
является бесплатным, работает довольно эффективно, однако исходный код
данного продукта недоступен, что сильно снижает его популярность.
Компания Google является лидером в области поисковых технологий[7].
Поэтому решение от данной компании является наиболее надежным и
эффективным, однако из-за того, что данный сервис является платным, многие
программисты смотрят в первую очередь на Open Source проекты, в которых они
могут разобраться и которые имеют обширную документацию. В первую
очередь это Sphinx и Lucene.
5.3.
Цели и преимущества использования Lucene
Главная задача Lucene – решить проблему, с которой сталкивается любой
разработчик: избыток информации. Lucene – это высокопроизводительная
масштабируемая библиотека информационного поиска. Сейчас она является
самой популярной свободной библиотекой информационного поиска. Lucene
предоставляет простой, но очень мощный API, который требует минимума
понимания механизмов текстовой индексации и поиска.
Основные преимущества использования данного поискового решения[15]:
1.
Ранжированный поиск.
2.
Большое количество типов запросов (Queris).
a.
wildcard запросов,
38
b.
запрос фразы,
c.
нечеткий поиск,
d.
поиск с использованием стемминга и лемматизации,
e.
поиск по интервалам.
3.
Требуется маленький объем RAM.
4.
Размер индекса составляет 20-30% от размера самого текста.
5.
Поиск по структурированному и гетерогенному контенту.
6.
Быстрый поиск по большим объемам данных.
7.
Использование встроенных анализаторов и возможность расширения
библиотеки с помощью собственных классов.
8.
Использование настраиваемых фильтров.
9.
Простота внедрения в уже существующее приложение.
5.4.
Дочерние проекты Lucene
ApacheLucene является базовым для многих проектов верхнего уровня
ApacheSoftwareFoundation, таких как [18]:
1. Nutch
2. Solr
3. Hadoop
4. Lucene.NET
5. Apache Mahout
6. Apache Tika
7. Compass.
39
Поэтому в нем реализованы самые современные технологии и подходы, в
том числе с поддержкой распределенных вычислений, что способствует
проникновению технологии в проекты с высокой нагрузкой и распределенных
веб-приложений.
5.5.
Проекты и фирмы, использующие данное поисковое
решение
На данный момент Lucene поддерживают такие проекты, как [16]:
CiteSeerX
- поисковая система и цифровая библиотека с акцентом на
компьютерные и информационные науки. Ее фонд насчитывает около 750 000
документов.
Twitter – всемирно известный сервер цитат, статусов и коротких сообщений.
Liferay – CMS, которая использует в качестве поисковика Lucene.
НанейфункционируютсайтыУлицыСезам, Cisco Developer Network, Societe
Generale Group.
IBM – фирма, не нуждающаяся в представлении, лидер в области высокой
технологии.
LinkedIn – социальная сеть, для людей, которые хотят найти работу. Более
150 млн пользователей. Содержит вакансии крупнейших компаний.
Существуют и многие другие проекты и продукты, которые используют
Luceneпри работе с большими объемами данных.
5.6.
Схема работы
Система Lucene состоит из 2 главных компонентов: индексатор и поисковик.
Индексатор работает непосредственно с данными типа byte, что обеспечивает
очень быстрый доступ. При этом он работает с применением многопоточности,
что позволяет получать индексы максимально быстро. Формирование индекса
происходит в несколько этапов[15]:
40
Указание источника контента (не зависит от типа источника, это может быть
как база данных, так и файл).
Запуск класса IndexWriter для чтения контента. Чтение файла происходит в
несколько потоков:
1) Удаление стоп-слов, предлогов, союзов, частиц;
2) использование анализаторов;
3) отбрасывание окончаний и учет морфологии того языка, который нам
нужен;
4) создание объекта типа Document;
5) добавление объекта Field к Document;
6) указание типа Field;
7) сериализация объекта в файл.
Поиск по индексу происходит следующим образом (рис. 5.6.1.):
1. Пользователь вводит через пользовательский интерфейс свой поисковый
запрос;
2. Выполняется построение поискового запроса типа Query.
3. Начинают работать анализаторы.
4. Десериализация объекта Document из файла.
5. Поиск по Field каждого объекта Document.
a.
Каждое поле Field проверяется на атомарность (в качестве
атомарного объекта может выступать как строка, так и подстрока).
b.
Если поле не атомарно, то происходит дополнительное
разбиение.
c.
Все поля сортируются в алфавитном порядке.
41
d.
Выполняется двоичный поиск.
e.
Для каждого совпадения, в зависимости от типа поиска
формируется свой вес Weight.
6. Происходит ранжирование результатов поиска в зависимости от Weight.
7. Каждый результат поиска заносит в массив результатов типа Hits.
8. Результат поиска Hits преобразуется в тот вид, в котором он будет выводится
пользователю.
9. Вывод данных поиска пользователю.
42
Рис.5.6.1. Схема работы Lucene
5.7.
Практическое использование Lucene
Использовать библиотеку Lucene на практике довольно просто. Для этого
достаточнодополнить свой программный код следующими строками и запустить
индексатор Lucene[28]
try {
List<String>docIdList = parsedDocsService.getDocumentIds(groupId);
43
IndexWriterindexWriter = newIndexWriter(indexDir, new StandardAnalyzer(),
false);//Создаемобъект, которыйбудетзаписыватьиндексывдиректориюindexDir
for(String docId : docIdList) {
indexDocument(indexWriter, parsedDocsService.loadDocument(docId));
}//Формируем индекс на основе загруженных документов и сохраняем его
indexWriter.close();//Закрываем поток объект IndexWriter
}
catch(IOException ioX) {
throw new RuntimeException("Error while creating lucene index: ", ioX);
}
Данный фрагмент кода выполняет формирование индексов IndexWriter на
основе имеющихся данных parsedDocsService.loadDocument(docId) с помощью
стандартного анализатора StandardAnalyzer, с помощью которого выполняется
стемминг и исключаются предлоги и союзы. Возможно использование других
анализаторов, встроенных в Lucene или написанных собственноручно.
Для поиска используется следующая конструкция:
try {
indexSearcher
=
newIndexSearcher(FSDirectory.getDirectory(indexDir));
//Указываемместо, вкоторомбудемпроизводитьпоиск
} catch (IOException ioX) {
System.out.println("ERROR: "+ioX.getMessage());
}
QueryParser
qp
=
new
QueryParser("content",
new
StandardAnalyzer());//Производиманализпоисковогозапроса
Query q = null;
try {
q = qp.parse(query);
} catch (ParseException pX) {
System.out.println("ERROR: "+pX.getMessage());
}
44
Hits hits = null;
try {
hits = indexSearcher.search(q); //получаемрезультатыпоиска
indexSearcher.close();
} catch (IOException ioX) {
System.out.println("ERROR: "+ioX.getMessage());
}
Создаем объект IndexSearcher, который берет данные из indexDirectory, в
которой хранятся индексы. Создаем QueryParser, который обрабатывает запрос
пользователя и преобразует его в язык запросов Lucene. Далее выполняем поиск
IndexSearcher.search(q)
и
получаем
результаты
поиска
hits
вместе
с
ранжированием.
5.8.
Выводы
Библиотека ApacheLucene является одним из наиболее популярных
поисковых решений в мире. Этому способствует большой спектр причин. Над
ней
работает
сообщество
профессионалов
из
разных
компаний
Google,Oracle,IBM и других. Однако внести вклад в ее развитие может любой
желающий. Высокая скорость работы, масштабируемость поисковых решений,
которая позволяет внедрять поиск в проектах самых разных уровней – большие
преимущества библиотеки.
Распространенность и обширная документация
позволяют библиотеке занимать лидирующее место среди остальных поисковых
проектов.
Основным мотивом ее применения стало то, что она уже содержит
встроенный индексатор, который обеспечивает достаточное быстродействие,
содержит большое количество инструментов для анализа и нахождения
необходимых
результатов.
используется,
что
Библиотека
позволяет
проще
активно
развивается
и
широко
получать
поддержку
сообщества
разработчиков, а также гарантирует множество примеров программного кода для
эффективного
внедрения
библиотеки
в
собственные
проекты.Ввиду
45
перечисленных преимуществ и особенностей работы библиотеки показалось
целесообразным ее использование в системе интеллектуального поиска.
46
6.Разработка методов снижения утомляемости
оператора многопрофильной системы информационного
поиска
6.1.
Общие сведения.
Зачастую работа оператора многопрофильной системы информационного
поиска отличается высоким нервно-эмоциональным напряжением.
Разделяют физическое и умственное утомление. Так, при тяжелом
физическом утомлении умственная работа малопродуктивна, и наоборот, при
умственном утомлении падает мышечная работоспособность. При умственном
утомлении отмечается расстройство внимания, ухудшение памяти и мышления.
Повышение работоспособности и снижение утомляемости достигается за счет
повышения квалификации работников и технического совершенствования
производственного процесса.
Можно выделить следующие существенные факторы условий труда [23]:

санитарно-гигиенические
–
освещение,
температура
воздуха,
запыленность, шум, электромагнитные излучения;

психофизиологические – рабочее место, поза, режим работы, нервно-
эмоциональная и интеллектуальная нагрузка;

технические – техническая безопасность оборудования.
Рассматривая влияние компьютеров на здоровье человека, можно выделить
следующие факторы риска: электромагнитное излучение, нагрузка на костномышечный аппарат, уровень шума, большие зрительные нагрузки.
Рассмотрим типы требований к эргономике рабочего места и к условиям
труда. Согласно ГОСТ Р 50923-96 конструкция рабочего места и взаимное
расположение всех его элементов должно соответствовать антропометрическим,
физическим и психологическим требованиям. Большое значение имеет также
сидячий характер работы, когда оператор весь день проводит у компьютера. При
47
организации рабочего места оператора (рабочий стол с компьютером) должны
быть соблюдены следующие основные условия:
 оптимальное размещение оборудования в составе рабочего места;
 достаточное рабочее пространство, позволяющее осуществлять все
необходимые движения и перемещения (600-800 см глубины стола и 1200-1600
ширины);
 необходимое освещение для выполнения поставленных задач, таких как
успешная работа оператора в течение дня (см. пункт 6.3, с. 45);
 уровень шума в рабочем пространстве не должен превышать допустимого
значения (пункт 6.5, с. 50).
6.2.
Общая характеристика рабочего места оператора
Главными элементами рабочего места оператора системы интеллектуального
поиска являются письменный стол и кресло. Основным рабочим положением
является положение сидя. Рабочее место для выполнения работ в положении
сидя организуется в соответствии с ГОСТ Р 50923-96 [23].
Рабочая поза сидя вызывает минимальное утомление программиста.
Рациональная планировка рабочего места предусматривает четкий порядок и
постоянство размещения предметов, средств труда и документации. То, что
требуется для выполнения работ чаще, расположено в зоне легкой досягаемости
рабочего пространства [23].
Моторное
поле
осуществляться
-
пространство
двигательные
рабочего
действия
места,
человека.
в котором могут
Максимальная
зона
досягаемости рук - это часть моторного поля рабочего места, ограниченного
дугами, описываемыми максимально вытянутыми руками при движении их в
плечевом суставе.
При проектировании компьютерного стола следует учитывать следующее:
 высота стола должна быть выбрана с учетом возможности сидеть
свободно, в удобной позе, при необходимости опираясь на подлокотники;
48
 нижняя часть стола должна быть сконструирована так, чтобы оператор мог
удобно сидеть, не был вынужден поджимать ноги;
 поверхность
стола
должна
обладать
свойствами,
исключающими
появление бликов в поле зрения оператора;
 конструкция стола должна предусматривать наличие выдвижных ящиков
для хранения документации, листингов, канцелярских принадлежностей.
Важным элементом рабочего места оператора является кресло. Оно
выполняется в соответствии с ГОСТ Р 50923-96. При проектировании кресла
исходят из того, что при любом рабочем положении программиста его поза
должна быть физиологически правильно обоснованной, т.е. положение частей
тела должно быть оптимальным. Для удовлетворения требований физиологии,
вытекающих из анализа положения тела человека в положении сидя,
конструкция рабочего сидения должна удовлетворять следующим основным
требованиям:
допускать
возможность
изменения
положения
тела,
т.е.
обеспечивать свободное перемещение корпуса и конечностей тела друг
относительно друга; допускать регулирование высоты в зависимости от роста
работающего человека ( в пределах от 400 до 550 мм ); иметь слегка вогнутую
поверхность, иметь небольшой наклон назад [3].
Исходя из вышесказанного, приведем параметры стола оператора:
 высота стола 710 мм;
 длина стола 1300 мм;
 ширина стола 650 мм;
 глубина стола 400 мм.
Важным моментом является также рациональное размещение на рабочем
месте документации, канцелярских принадлежностей, что должно обеспечить
работающему удобную рабочую позу, наиболее экономичные движения и
минимальные траектории перемещения работающего и предмета труда на
данном рабочем месте.
49
6.3.
Проблемы перегрузки зрения. Основные требования к
освещению и цветовому оформлению помещений
Утомление зрения при работе с компьютером вызывается мерцанием,
дрожанием
изображения
на
экране.
Более
всех
страдают
операторы,
занимающиеся считыванием текстовой информации: чем мельче символ, тем
больше нагрузка на зрение. Основные требования к освещению изложены в
соответствии с ГОСТ Р-50923-96[21].
Возникновению
зрительного
утомления
способствует
использование
неблагоприятных цветовых сочетаний и неправильная организация освещения в
помещении. Яркое и неровное освещение вызывает нежелательные отражения,
блики на экране. Для устранения блесткости используют матовые поверхности,
оборудуют светопроемы шторами или жалюзи, размещают рабочий стол так,
чтобы оконный проем находился сбоку, и при этом дисплей должен
располагаться на поверхности стола справа или слева от оператора. Для
освещения зоны расположения документов допускается установка светильников
местного освещения.
Монитор,
используемый
при
работе,
должен
иметь
гигиенический
сертификат и маркировку соответствия РосСтандарт [21]. Конструкция монитора
должна обеспечивать возможность фронтального наблюдения экрана путем
поворота корпуса в горизонтальной плоскости вокруг вертикальной оси и в
вертикальной плоскости вокруг горизонтальной с фиксацией в заданном
положении [25]. Чтобы уменьшить нагрузку на зрение, надо учитывать
рекомендации. При работе с монитором расстояние до монитора должно быть
равно 450 – 700 мм. Экран дисплея по высоте должен быть расположен так,
чтобы угол между нормалью к центру экрана и горизонтальной линией взгляда
составлял 20 градусов. Документ для ввода данных рекомендуется располагать
на расстоянии 50 см слева от глаз оператора. Угол наклона клавиатуры должен
быть равен 15 градусам.
Экран дисплея, документы и клавиатура располагают так, чтобы перепад
яркостей поверхностей, зависящий от их расположения относительно источника
50
света,
не
превышал
1:10
(рекомендуемое
значение
1:3).
Устройства
документирования и нечасто используемые технические средства рекомендуется
располагать справа от оператора в зоне досягаемости, а средства связи слева,
чтобы освободить правую руку для записей.
Результат снижения утомляемости при работе при работе с компьютером
дает правильная организация труда и отдыха. Согласно рекомендациям НИИ
гигиены труда и профзаболеваний АМН РФ рабочий день за компьютером
должен быть не более 6 часов, с дополнительными перерывами по 3 минуты
через каждые полчаса, а через 2 часа работы по 15 – 20 минут [25].
Основной
задачей
рациональной
организации
освещения
является
поддержание освещенности, соответствующей характеру зрительной работы [4].
При
организации
распределение
освещения
яркости.
необходимо
Перевод
взгляда
обеспечить
с
ярко
равномерное
освещенной
на
слабоосвещенную поверхность вынуждает глаз переадаптироваться, что ведет к
утомлению зрения. Светлая окраска потолка и стен способствует равномерному
распределению яркостей в поле зрения. Освещение должно обеспечивать
отсутствие в поле зрения резких теней. Они искажают размеры и формы
объектов,
повышают
утомляемость.
Тени
можно
смягчать,
применяя
светильники со светорассеивающими стеклами. При подборе цвета для
цветового оформления необходимо учитывать допустимые степени контрастов
между используемым предметом и фоном. При сочетаниях одновременно
наблюдаются контрасты по яркости, цветовому тону и насыщенности.
Для улучшения видимости объектов должна отсутствовать прямая и
отраженная блесткость. Ее ограничивают уменьшением яркости источников
света, правильным выбором защитного угла светильника, увеличением высоты
подвеса светильников, правильным направлением светового потока. Блестящие
поверхности следует заменить матовыми.
Колебания освещенности на рабочем месте обусловливают переадаптацию
глаза, приводя к значительному утомлению. Постоянство освещенности
51
достигается стабилизацией питающего напряжения, жестким креплением
светильников, применением специальных схем включения газоразрядных ламп.
При организации освещения следует выбирать необходимый спектральный
состав светового потока. Это особенно существенно для обеспечения
правильной цветопередачи. Оптимальный спектральный состав обеспечивает
естественное освещение.
Все эти требования учитываются действующими нормами проектирования и
правилами
эксплуатации
пространствах.
Основным
освещения
в
помещениях
нормативным
документом,
и
на
открытых
регламентирующим
нормы проектирования является СНиП[31].
Естественное освещение должно осуществляться через светопроемы,
ориентированные преимущественно на север и северо-восток и обеспечивать
коэффициент естественной освещенности (КЕО) не ниже 1,2% в зонах с
устойчивым снежным покровом и не ниже 1,5% на остальной территории.
Указанные значения КЕО нормируются для зданий, расположенных в III
световом климатическом поясе. Расчет КЕО для других поясов светового
климата проводится по общепринятой методике согласно СНиП "Естественное и
искусственное освещение" [31].
Цвет также является мощным биологическим фактором, оказывающим в
одном случае стимулирующее влияние на человека, на восприятие им
информации из внешней среды, в другом – угнетающее, когда возникает
утомление. Применяемые цвета должны создавать необходимые физиологически
благоприятные условия для органов зрения и всей центральной нервной системы
человека, весьма чувствительной к цвету.
Восприятие цвета окрашенного предмета зависит от фона, от сочетания
цветов, уровня освещенности, спектрального состава источников света, углового
размера наблюдаемых предметов, взаимного геометрического расположения
цветов, с учетом их эстетического влияния. Видимый цвет предметов
определяется совокупностью указанных выше условий.
52
К
числу
раздражителей
относятся
световые
и
цветовые
потоки,
отражающиеся от стен и потолков, оборудования. Влияние этих раздражителей
зависит от свойств отражающих поверхностей и осветительных установок.
Поэтому существенное значение имеют коэффициенты отражения в помещениях
[31], которые могут изменить впечатление о высоте и объеме комнаты. От этих
коэффициентов зависит также и освещенность помещения.
Окраска стен комнаты и находящихся в ней предметов воспринимается поразному
при
дневном
и
искусственном
освещении.
Изменение
цвета
поверхности при ее освещении разными лампами зависит от типа ламп. Цвет
поверхности почти не меняется при освещении лампами ЛДЦ [31]. При
освещении другими лампами цвет поверхности довольно сильно меняется.
Каждый
цвет
имеет
свою
физическую
и
психо-физиологическую
характеристику, воздействие которых проявляются во взаимосвязи с остальными
условиями
среды.
Рациональное
цветовое
оформление
помещений
–
действенный фактор улучшения условий труда и жизнедеятельности [26].
В помещениях с окнами, выходящими на юг, а также в помещениях с
избытком солнечного света рекомендуется преимущественно использовать
зеленые, зелено-голубые и голубые цвета. В помещениях с окнами, выходящими
на север, и в помещениях, где ощущается недостаток дневного света, следует
использовать светлые оттенки теплых цветов.
При создании оптимальной цветовой производственной среды, помещения
следует окрашивать в светлые цвета малой насыщенности, расположенные в
средневолновой
зоне
(оранжево-желтый,
желтовато-зеленый,
зеленый,
голубовато-зеленый, зеленовато-голубой и голубой цвета). Потолки и самый
верх стен должны быть белыми (это повышает равномерность освещения).
При работе, требующей большой сосредоточенности, лучше применять
«холодные» цвета. Эти цвета должны быть светлыми, слабонасыщенными и
малоконтрастными.
Разностороннее эмоциональное воздействие цвета на человека позволяет
широко использовать его в гигиенических целях.
53
6.4.
Нагрузка на костно-мышечный аппарат. Снижение
физических нагрузок
Сидячая продолжительная работа вредна человеку в принципе: он сутулится
или подается вперед и позвоночник деформируется, травмируя диски; человек
поднимает плечи и сгибает руки, держа их в напряжении - и естественно они
начинают болеть. Поза, а следовательно и здоровье, а следовательно, и
результативность работы, зависят от размеров и дизайна рабочего места.
Неподвижная напряженная поза оператора, вынужденного в течение
длительного времени находиться у экрана дисплея, приводит к усталости,
возникновению болей в позвоночнике, шее, плечевых суставах. А интенсивная
работа с клавиатурой и мышью вызывает болевые ощущения в локтевых
суставах, предплечьях, запястьях, в кистях и пальцах рук. Конструкция
клавиатуры должна соответствовать СанПиН.
Так же по санитарным правилам и нормам для взрослого человека должны
быть выполнены требования СанПиН 2.2.2.542-96 [21, 2, 29].
Правильная посадка человека представлена на рис. 6.4.1.
Рис.6.4.1 Правильная позиция за компьютером
Согласно рекомендациям НИИ гигиены труда и профзаболеваний АМН РФ
рабочий
день
за
компьютером
должен
быть
не
более
6
часов,
с
дополнительными перерывами по 3 минуты через каждые полчаса, а через 2 часа
работы по 15-20 минут.
54
6.5.
Требования к микроклимату и ненормированный
уровень шумов
Современные ПК имеют системы охлаждения на основе вентиляторов
различных типов, которые могут являться источником шума. В системном блоке
могут работать от двух до шести вентиляторов. Офисы должны быть
оборудованы кондиционерами. Поэтому в помещениях с компьютерами
создаётся превышающий норму уровень шума, вырабатываемого вентиляторами
в системных блоках и кондиционерами. Также присутствуют шумы, издаваемые
накопителями на жестком и мягком магнитных дисках, принтерами, сканерами
[20].
Все это оказывает влияние на психику и состояние человека, вызывая
чувства стесненности, тревоги. На рабочих местах уровень шума не должен
превышать 75 дБа. Для снижения уровня шумов используют звукоизолирующие
преграды, стены и потолки отделывают специальными пористыми плитами,
поглощающими звук.
Работа компьютеров и других устройств связана с выделением тепла. При
высокой температуре воздуха у людей, работающих в помещениях, возникает
перегрев организма, поэтому пользователь теряет внимание.
Работа пользователя по энергозатратам организма относится к 1 категории
работ, т.е. работ легкой категории, которая выполняется сидя и затраты энергии
не превышают 150 Ккал/час. Этой категории соответствуют оптимальные нормы
параметров микроклимата, приведенные в табл. 6.5.1. [21]:
Период
года
Температур
а воздуха, С
Не более
Относительна
я
Скорость
влажность движения
воздуха, %
воздуха,
м/с
Холодн
22 –24
40 – 60
0,1
Теплый
23 – 25
40 – 60
0,1
ый
55
Таблица 6.5.1. Оптимальные нормы параметров микроклимата
6.6.
Специфика факторов утомляемости оператора
многопрофильной системы интеллектуального поиска
Оператор многопрофильной системы интеллектуального поиска испытывает
воздействие дополнительных факторов, вызывающих усталость. Среди них:
необходимость выбирать подходящие формулировки для поисковых запросов,
размышления об особенностях поиска для получения нужного результата.
Последствиями могут быть опять же головная боль, усталость (также синдром
хронической усталости [5]), глазные заболевания – а также усиления описанных
в других пунктах последствий.
6.7. Выводы
Таким образом, рассмотрены несколько видов нагрузок на человеческий
организм: нагрузка на глаза, костно-мышечный аппарат, повышенный уровень
шума, электромагнитное излучение, нарушения микроклимата.
Предложены мероприятия по снижению нагрузок и основные требования к
организации рабочего места, регулируемые нормативными документами (ГОСТ
Р 50923-96).
В условиях напряженного труда необходимо соблюдать требования к
организации рабочего места и труда в целом. В этом случае достижимы хорошие
результаты работы в сочетании с безопасностью оператора и сохранением
здоровья.
56
7.Заключение.
В данной работе рассмотрены вопросы реализации информационного поиска.
Внедрение алгоритмов интеллектуального поиска является сложной задачей, так
как количество и структура доступной для обработки информации – это
непостоянная
величина.
С
ростом
интернета
доступность
информации
увеличилась, что еще больше затруднило задачу поиска в источниках различного
рода. Появилось большое множество проектов, которые, так или иначе,
используют интеллектуальные алгоритмы обработки данных. Однако многие
алгоритмы и методики, которые используются в подобного рода приложениях,
труднодоступны для большинства разработчиков, так как коммерческий
потенциал применения таких приложений высок, поэтому многие фирмы
стараются защитить собственные разработки с помощью авторского и
патентного права, скрыв важные детали реализации. Еще одна причина, почему
распространение данных методик ограничено, связана с тем, что их понимание и
разработка требует значительной математической подготовки разработчика, а
также требует значительных временных и трудовых ресурсов для создания
необходимых методик. В своей работе мы постарались охватить некоторые из
них,
однако
данное
направление
исследований
видится
довольно
перспективным, поэтому архитектура системы информационного поиска
предполагает расширение и добавление новых алгоритмов, что позволит
повысить эффективность системы информационного поиска.
Главная задача, стоящая перед разработчиком системы информационного
поиска, в том, чтобы выбрать те алгоритмы, которые будут корректно работать
для тех данных, в которых нужно произвести поиск. Использование каждой
методики в отдельности: кластеризация, классификация, полнотекстовый поиск,
стемминг, лемматизация – оказывается малоэффективным, поэтому необходимо
использовать весь комплекс поисковых решений и алгоритмов, чтобы система
информационного поиска находила необходимые результаты при указанном
количестве времени. Были реализованы два основных компонента: 1)подсистема
поисковых агентов, 2) подсистема сбора, анализа и хранения. Подсистема
57
поисковых агентов представляет собой совокупность автономных программных
модулей,
осуществляющих
индексацию
гетерогенных
информационных
массивов в глобальных и локальных сетях. Подсистема сбора и анализа данных
обеспечивает: обработку пользовательских запросов, прием и хранение
информации от поисковых агентов, производит оценку релевантности между
запросами
и
индексированным
контентом
с
использованием
методов
интеллектуального анализа данных. В данной работе были рассмотрены
следующие алгоритмы информационного поиска: DBSCAN, алгоритм ROCK,
наивный Байесовский классификатор, алгоритм PageRank. Каждый из этих
алгоритмов
решает
свои
задачи,
которые
встают
перед
системой
информационного поиска, поэтому позволяет ей лучше справляться со своими
функциями.
Таким образом, техническое задание на дипломный проект выполнено в
полном объеме и в сроки, установленные календарным планом.
58
Использованные источники
1. Автоматическая
обработка
текстов
на
естественном
языке
и
компьютерная лингвистика: учеб.пособие / Большакова Е.И [и др.] — М.:
МИЭМ, 2011. - 272 с.
2. Безопасность жизнедеятельности / Под общ.ред. Белова С.В. 7-е изд. – М.:
Высшая школа, 2007.— 616 с.
3. Безопасность жизнедеятельности/Под ред. О.Н.Русака–СПб: ЛТА, 1996. –
429.
4. Белов, С.В. Безопасность жизнедеятельности. Учебник для вузов. /С.В.
Белов, А.В. Ильинская, А.Ф. Козьяков и др. –М.: Высш. шк., 1999. – 448 с.
5. Белов, С.В. Безопасность жизнедеятельности. Учебник для студентов
средних проф. учеб. Заведений/С.В. Белов, В.А. Девисилов, А.Ф. Козьяков
и др. – М.: Высшая школа, НМЦ СПО, 2000. – 356 с.
6. Белоусов, К. И. Синергетика текста: От структуры к форме. – М.:
Книжный дом «ЛИБРОКОМ», 2008. – 248 с.
7. Информационный ресурс «Google» [Электронный ресурс] – Режим
доступа:http://google.com.
8. Информационный ресурс «Wikipedia», статья «Семантические сети»
[Электронный
ресурс]
–
Режим
доступа:
http://ru.wikipedia.org/wiki/Семантическая_сеть
9. Информационный ресурс«Xapian» [Электронный ресурс] – Режим доступа:
http://xapian.org.
10. Информационный ресурс «Алгоритмы кластеризации, Гиршов Е.»
[Электронный
ресурс]
–
Режим
доступа:http://www.krelib.com/files/math/Klaster_Girch.pdf
11. Информационный ресурс«Яндекс» [Электронный ресурс] – Режим
доступа: http://yandex.ru.
59
12.Информационный сайт «AskNet», статья «Семантические поисковые
системы» [Электронный ресурс] – Режим доступа: http://asknet.ru/
13.Информационный сайт «CherubicSoft», страница «Лицензия GPL 2 порусски»
[Электронный
ресурс]
–
Режим
доступа:
http://www.cherubicsoft.com/license_rus.txt#.T7XUs1LPzQQ
14. Информационный сайт «HostSolutions», страница «Алгоритм PageRank:
изнутри»
[Электронный
ресурс]
–
Режим
доступа:
http://host-
solutions.ru/cms-joomla/instruction-joomla/242-pagerank.html
15. Информационный сайт «Lucene» [Электронный ресурс] – Режим доступа:
http://lucene.apache.org/
16. Информационный сайт «Lucene-javaWiki»[Электронный ресурс] – Режим
доступа: http://wiki.apache.org/lucene-java/PoweredBy
17.Информационный
сайт
«Sphinx»[Электронный
ресурс]
–
Режим
доступа:http://sphinxsearch.com Официальный сайт аналога библиотеки
Lucene
18.Информационныйсайт«TheApacheSoftwareFoundation»[Электронный
ресурс] – Режим доступа: http://www.apache.org/
19. Информационный
сайт
«TheApacheSoftwareFoundation»,
статья
«ApacheLicense, Version 2.0» [Электронный ресурс] – Режим доступа:
http://www.apache.org/licenses/LICENSE-2.0
20.Информационный сайт «Автоматизированная система “Оперативный
анализ параметров абонентских линий” И.В. Деревянко» [Электронный
ресурс]
–
Режим.доступа:
http://www.delaemna5.ru/files/diplomy/kommunikacii_svyaz/sobrall.doc
21.Информационный сайт «Государственный стандарт РФ. Дисплеи. Рабочее
место оператора. Общие эргономические требования и требования к
производственной среде. Методы измерения» [Электронный ресурс] –
Режим
доступа:
60
http://bezopasnostplus.com/bezopasnost/prom_bezopasnosti/instruktsiyaoperatora-evm-po-ohrane-truda-mozhno-skachat
22.Информационный сайт «Интеллектуальный поиск в глобальных и
локальных вычислительных сетях и базах данных,Г. С. Осипов, И. А.
Тихомиров,
И.
В.
Смирнов»
[Электронный
ресурс]
–
Режим
доступа:http://www.google.ru/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1
&ved=0CFYQFjAA&url=ftp%3A%2F%2Fwww.botik.ru%2Frented%2Fpsi%2
Fwww%2FPSI%2Fdisk_20%2Fe-book%2Fe-book%2F2-5%2F02-OsipovIntellektualnyj-poisk-p-21.pdf&ei=ZmvXTbmDYPImQXTgOH2Ag&usg=AFQjCNFWVtp0tZI4xVAzkNEp2SJGkBXpG
A&sig2=trYLTTmKWltmPR7lb_wpUQ
23.Информационный
сайт
«Охрана
программиста»[Электронный
труда
ресурс]
на
рабочем
–
месте
Режим
доступа:www.culon.ru/download/culon-2796.doc
24.Информационный сайт «Растолкованный PageRank»[Электронный ресурс]
– Режим доступа:http://www.digits.ru/articles/promotion/pagerank.html
25.Кукин,
П.П.
Безопасность
жизнедеятельности.
Безопасность
технологических процессов и производств (Охрана труда): Учебное
пособие для вузов/ П.П. Кукин, В.Л. Лапин, Е.А. Подгорных и др. – М.:
Высш. шк., 1999. - 318с.
26.Луизов, А.В. Цвет и свет. – Л.: Энергоатомиздат. Ленингр. отд-ние, 1989.–
256с.
27.Маннинг, Кристофер Д.Введение в информационный поиск. /Кристофер
Д.Маннинг, Прабхакар Рагхаван, Хайнрих Шютце: Пер. с англ. – М.: ООО
«И.Д. Вильямс», 2011. – 528 с.
28.Марманис Х., Бабенко Д. Алгоритмы интеллектуального интернета.
Передовые методики сбора, анализа и обработки данных. – Пер. с англ. –
СПб.: Символ-Плюс, 2011. – 480 с.
61
29.Мунипов, В.М. Основы эргономики./В.М. Мунипов, В. П. Зинченко.
Учебное пособие. М., 1979. – 344 с.
30.Орлов, Ю. Н. Методы статистического анализа литературных текстов./Ю.
Н. Орлов, К. П. Осминин. – М. кн. дом «ЛИБРОКОМ», 2012. – 312.
31.Тесленко И.М. Освещение производственных помещений: Учебное
пособие. – Хабаровск: Изд-во ДВГУПС, 2001. – 58 с.
62
Приложение А.
Исходный код программы
NaiveBayes
package ru.aetet.drillsearcher.algos.bayes.bayes;
import ru.aetet.drillsearcher.algos.bayes.Attribute;
import ru.aetet.drillsearcher.algos.bayes.AttributeValue;
import ru.aetet.drillsearcher.algos.bayes.Concept;
import ru.aetet.drillsearcher.algos.bayes.Instance;
import ru.aetet.drillsearcher.algos.bayes.classification.TrainingSet;
import ru.aetet.drillsearcher.algos.bayes.classification.intf.Classifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class NaiveBayes implements Classifier {
private String name;
protected TrainingSet tSet;
protected Map<Concept,Double> conceptPriors;
protected Map<Concept,Map<Attribute, AttributeValue>> p;
protected ArrayList<String> attributeList;
protected boolean verbose = false;
public NaiveBayes(String name, TrainingSet set) {
this.name = name;
tSet = set;
conceptPriors = new HashMap<Concept,Double>(tSet.getNumberOfConcepts());
verbose = false;
}
public Concept classify(Instance instance) {
Concept bestConcept = null;
double bestP = 0.0;
if( tSet == null || tSet.getConceptSet().size() == 0) {
throw new RuntimeException("You have to train classifier first.");
}
if( verbose ) {
System.out.println("\n*** Classifying instance: " + instance.toString() + "\n");
}
for (Concept c : tSet.getConceptSet()) {
double p = getProbability(c, instance);
if( verbose ) {
System.out.printf("P(%s|%s) = %.15f\n", c.getName(), instance.toString(), p);
}
if( p >= bestP ) {
bestConcept = c;
bestP = p;
63
}
}
return bestConcept;
}
public boolean train() {
long t0 = System.currentTimeMillis();
boolean hasTrained = false;
if ( attributeList == null || attributeList.size() == 0) {
System.out.print("Can't train the classifier without specifying the attributes for
training!");
System.out.print("Use the method --> trainOnAttribute(Attribute a)");
} else {
calculateConceptPriors();
calculateConditionalProbabilities();
hasTrained = true;
}
if (verbose) {
System.out.print("
Naive Bayes training completed in ");
System.out.println((System.currentTimeMillis()-t0)+" (ms)");
}
return hasTrained;
}
public void trainOnAttribute(String aName) {
if (attributeList ==null) {
attributeList = new ArrayList<String>();
}
attributeList.add(aName);
}
private void calculateConceptPriors() {
for (Concept c : tSet.getConceptSet()) {
int totalConceptCount=0;
for (Instance i : tSet.getInstances().values()) {
if (i.getConcept().equals(c)) {
totalConceptCount++;
}
}
conceptPriors.put(c, new Double(totalConceptCount));
}
64
}
protected void calculateConditionalProbabilities() {
p = new HashMap<Concept, Map<Attribute, AttributeValue>>();
for (Instance i : tSet.getInstances().values()) {
for (Attribute a: i.getAtrributes()) {
if (a != null && attributeList.contains(a.getName())) {
if ( p.get(i.getConcept())== null ) {
p.put(i.getConcept(), new HashMap<Attribute,
AttributeValue>());
}
Map<Attribute, AttributeValue> aMap = p.get(i.getConcept());
AttributeValue aV = aMap.get(a);
if ( aV == null ) {
aV = new AttributeValue(a.getValue());
aMap.put(a, aV);
} else {
aV.count();
}
}
}
}
}
public double getProbability(Concept c, Instance i) {
double cP=0;
if (tSet.getConceptSet().contains(c)) {
cP = (getProbability(i,c)*getProbability(c))/getProbability(i);
} else {
cP = 1/(tSet.getNumberOfConcepts()+1.0);
}
return cP;
}
public double getProbability(Instance i) {
double cP=0;
for (Concept c : getTset().getConceptSet()) {
cP += getProbability(i,c)*getProbability(c);
65
}
return (cP == 0) ? (double)1/tSet.getSize() : cP;
}
public double getProbability(Concept c) {
Double trInstanceCount = conceptPriors.get(c);
if( trInstanceCount == null ) {
trInstanceCount = 0.0;
}
return trInstanceCount/tSet.getSize();
}
public double getProbability(Instance i, Concept c) {
double cP=1;
for (Attribute a : i.getAtrributes()) {
if ( a != null && attributeList.contains(a.getName()) ) {
Map<Attribute, AttributeValue> aMap = p.get(c);
AttributeValue aV = aMap.get(a);
if ( aV == null) {
cP *= ((double) 1 / (tSet.getSize()+1));
} else {
cP *= (aV.getCount()/conceptPriors.get(c));
}
}
}
return (cP == 1) ? (double)1/tSet.getNumberOfConcepts() : cP;
}
public String getName() {
return name;
}
public TrainingSet getTset() {
return tSet;
}
}
BaseConcept
package ru.aetet.drillsearcher.algos.bayes;
import java.util.ArrayList;
public class BaseConcept implements Concept {
private String name;
private BaseConcept parent;
private ArrayList<Instance> instances = new ArrayList<Instance>();
public BaseConcept(String name) {
this.name = name;
}
66
public BaseConcept(String name, BaseConcept parent) {
this.name = name;
this.parent = parent;
}
public synchronized void addInstance(Instance i) {
instances.add(i);
}
public Instance[] getInstances() {
return instances.toArray(new Instance[instances.size()]);
}
public String getName() {
return name;
}
public Concept getParent() {
return parent;
}
public void setParent(BaseConcept parent) {
this.parent = parent;
}
@Override
public String toString() {
return name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((parent == null) ? 0 : parent.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
final BaseConcept other = (BaseConcept) obj;
if (this == obj) {
return true;
}
if ( !(obj instanceof BaseConcept) ) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
if (parent == null) {
if (other.parent != null) {
67
return false;
}
} else if (!parent.equals(other.parent)) {
return false;
}
return true;
}
}
BaseInstance
package ru.aetet.drillsearcher.algos.bayes;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
public class BaseInstance implements Instance {
protected Concept concept;
protected StringAttribute[] attributes;
public BaseInstance() {
public BaseInstance(Concept concept, StringAttribute[] attributes) {
this.concept = concept;
this.attributes = attributes;
}
public Attribute[] getAtrributes() {
return attributes;
}
public Concept getConcept() {
return concept;
}
public BaseInstance[] load(String fileName) throws IOException {
File
file = new File(fileName);
FileReader fReader = new FileReader(file);
BufferedReader bR = new BufferedReader(fReader);
return load(bR);
}
public BaseInstance[] load(BufferedReader bR) throws IOException {
ArrayList<BaseInstance> baseInstances = new ArrayList<BaseInstance>();
String line;
boolean hasMoreLines = true;
while (hasMoreLines) {
line=bR.readLine();
if (line == null) {
hasMoreLines = false;
} else {
String[] data = line.split(",");
int n = data.length;
StringAttribute[] attributes = new StringAttribute[n-1];
68
for (int i=0; i<n-1;i++) {
attributes[i] = new StringAttribute("a-"+i,data[i]);
}
baseInstances.add(new BaseInstance(new BaseConcept(data[n-1]),attributes));
}
}
return baseInstances.toArray(new BaseInstance[baseInstances.size()]);
}
public static BaseInstance createInstance(String conceptName, String[] attrNames, String[] attrValues) {
int n = attrNames.length;
StringAttribute[] attributes = new StringAttribute[n];
for (int i = 0; i < n; i++) {
attributes[i] = new StringAttribute(attrNames[i], attrValues[i]);
}
Concept concept = new BaseConcept(conceptName);
return new BaseInstance(concept, attributes);
}
public void print() {
if (attributes != null) {
for (Attribute a : attributes) {
if ( a == null || a.getName() == null) {
System.out.print(" - <NULL ATTRIBUTE> ");
} else {
if (a.getValue() == null) {
System.out.print(" - <NULL ATTRIBUTE VALUE> ");
} else {
System.out.print(" - "+a.getName()+" = "+a.getValue());
}
}
}
}
System.out.println(" --> "+getConcept().getName());
}
public void setConcept(Concept concept) {
this.concept = concept;
}
public StringAttribute getAttribute(int i) {
return attributes[i];
}
@Override
public boolean equals(Object obj) {
final BaseInstance other = (BaseInstance) obj;
if (this == obj) {
69
return true;
}
if ( (getClass() != obj.getClass()) || obj == null) {
return false;
}
if (concept == null) {
if (other.concept != null) {
return false;
}
} else {
if (!concept.equals(other.concept)) {
return false;
}
}
for (int i=0; i<attributes.length; i++) {
if (attributes[i] == null) {
if (other.attributes[i] != null) {
return false;
}
} else {
if (!attributes[i].getName().equals(other.attributes[i].getName())) {
return false;
} else {
if (!attributes[i].getValue().equals(other.attributes[i].getValue())) {
return false;
}
}
}
}
return true;
}
public Attribute getAttributeByName(String attrName) {
Attribute matchedAttribute = null;
if( attributes != null ) {
for(Attribute a : attributes) {
if( attrName.equalsIgnoreCase(a.getName())) {
matchedAttribute = a;
break;
}
}
}
return matchedAttribute;
}
}
LuceneIndexBuilder
package ru.aetet.drillsearcher.index.builder;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Field;
70
import org.apache.lucene.index.IndexWriter;
import ru.aetet.drillsearcher.util.crawling.core.CrawlData;
import ru.aetet.drillsearcher.util.crawling.db.ProcessedDocsDB;
import ru.aetet.drillsearcher.util.crawling.model.ProcessedDocument;
import ru.aetet.drillsearcher.util.crawling.runner.CrawlDataProcessor;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class LuceneIndexBuilder implements CrawlDataProcessor {
private File indexDir;
private CrawlData crawlData;
public LuceneIndexBuilder(File indexDir, CrawlData crawlData) {
this.indexDir = indexDir;
this.crawlData = crawlData;
try {
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(),
true);
indexWriter.close();
} catch (IOException ioX) {
throw new RuntimeException("Error while creating lucene index: ", ioX);
}
}
private void buildLuceneIndex(String groupId, ProcessedDocsDB parsedDocsService) {
try {
List<String> docIdList = parsedDocsService.getDocumentIds(groupId);
IndexWriter indexWriter = new IndexWriter(indexDir, new StandardAnalyzer(), false);
for(String docId : docIdList) {
indexDocument(indexWriter, parsedDocsService.loadDocument(docId));
}
indexWriter.close();
}
catch(IOException ioX) {
throw new RuntimeException("Error while creating lucene index: ", ioX);
}
}
private void indexDocument(IndexWriter iw, ProcessedDocument parsedDoc) throws IOException {
org.apache.lucene.document.Document doc = new org.apache.lucene.document.Document();
doc.add(new Field("content",
parsedDoc.getText(),
Field.Store.NO,
Field.Index.TOKENIZED,
Field.TermVector.YES));
doc.add(new Field("url",
parsedDoc.getDocumentURL(),
Field.Store.YES,
Field.Index.NO));
71
doc.add(new Field("docid",
parsedDoc.getDocumentId(),
Field.Store.YES,
Field.Index.NO));
doc.add(new Field("title",
parsedDoc.getDocumentTitle(),
Field.Store.YES,
Field.Index.NO));
doc.add(new Field("doctype",
parsedDoc.getDocumentType(),
Field.Store.YES,
Field.Index.NO));
iw.addDocument(doc);
}
public void run() {
List<String> allGroups = crawlData.getProcessedDocsDB().getAllGroupIds();
for(String groupId : allGroups) {
buildLuceneIndex(groupId, crawlData.getProcessedDocsDB());
}
}
}
PageRank
package ru.aetet.drillsearcher.index.ranking.impl;
import ru.aetet.drillsearcher.index.ranking.PageRankMatrixBuilder;
import ru.aetet.drillsearcher.index.ranking.PageRankMatrixH;
import ru.aetet.drillsearcher.index.ranking.Rank;
import ru.aetet.drillsearcher.util.crawling.core.CrawlData;
public class PageRank extends Rank {
PageRankMatrixBuilder pageRankBuilder;
public PageRank(CrawlData crawlData) {
pageRankBuilder = new PageRankMatrixBuilder(crawlData);
pageRankBuilder.run();
}
@Override
public PageRankMatrixH getH() {
return pageRankBuilder.getH();
}
}
PageRankMatrixBuilder
package ru.aetet.drillsearcher.index.ranking;
import ru.aetet.drillsearcher.util.crawling.core.CrawlData;
72
import ru.aetet.drillsearcher.util.crawling.db.KnownUrlDB;
import ru.aetet.drillsearcher.util.crawling.db.PageLinkDB;
import ru.aetet.drillsearcher.util.crawling.model.KnownUrlEntry;
import ru.aetet.drillsearcher.util.crawling.runner.CrawlDataProcessor;
import java.util.List;
import java.util.Set;
public class PageRankMatrixBuilder implements CrawlDataProcessor {
private PageRankMatrixH matrixH;
private CrawlData crawlData;
public PageRankMatrixBuilder(CrawlData crawlData) {
this.crawlData = crawlData;
}
public PageRankMatrixH getH() {
return matrixH;
}
public void run() {
this.matrixH = buildMatrixH(crawlData.getKnownUrlsDB(), crawlData.getPageLinkDB());
}
private PageRankMatrixH buildMatrixH(KnownUrlDB knownUrlDB, PageLinkDB pageLinkDB) {
List<String> allProcessedUrls =
knownUrlDB.findProcessedUrls(KnownUrlEntry.STATUS_PROCESSED_SUCCESS);
PageRankMatrixH pageMatrix = new PageRankMatrixH( allProcessedUrls.size() );
for(String url : allProcessedUrls) {
pageMatrix.addLink(url);
Set<String> pageOutlinks = pageLinkDB.getOutlinks(url);
for(String outlink : pageOutlinks) {
if( knownUrlDB.isSuccessfullyProcessed(outlink) ) {
pageMatrix.addLink(url, outlink);
}
}
}
pageMatrix.calculate();
return pageMatrix;
}
}
PageRankMatrixH
package ru.aetet.drillsearcher.index.ranking;
import ru.aetet.drillsearcher.util.crawling.util.ValueToIndexMapping;
73
public class PageRankMatrixH {
private ValueToIndexMapping indexMapping = new ValueToIndexMapping();
double[][] matrix;
private int numberOfPagesWithNoLinks = 0;
public PageRankMatrixH(int nPages) {
matrix = new double[nPages][nPages];
}
public int getNumberOfPagesWithNoLinks() {
return this.numberOfPagesWithNoLinks;
}
public double[][] getMatrix() {
return matrix;
}
public void addLink(String pageUrl) {
indexMapping.getIndex(pageUrl);
}
public void addLink(String fromPageUrl, String toPageUrl, double weight) {
int i = indexMapping.getIndex(fromPageUrl);
int j = indexMapping.getIndex(toPageUrl);
try {
matrix[i][j] = weight;
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("fromPageUrl:" + fromPageUrl + ", toPageUrl: " + toPageUrl);
}
}
public void addLink(String fromPageUrl, String toPageUrl) {
addLink(fromPageUrl, toPageUrl, 1);
}
public void calculate() {
for(int i = 0, n = matrix.length; i < n; i++) {
double rowSum = 0;
for(int j = 0, k = matrix.length; j < k; j++) {
rowSum += matrix[i][j];
}
if( rowSum > 0 ) {
for(int j = 0, k = matrix.length; j < k; j++) {
if( matrix[i][j] > 0 ) {
74
matrix[i][j] = matrix[i][j] / rowSum;
}
}
} else {
numberOfPagesWithNoLinks++;
}
}
}
public void print() {
StringBuilder txt = new StringBuilder("H Matrix\n\n");
for (int i = 0, n = matrix.length; i < n; i++) {
txt.append("Index: ").append(i);
txt.append(" --> ");
txt.append("Page ID: ").append(indexMapping.getValue(i));
txt.append("\n");
}
txt.append("\n").append("\n");
for (int i = 0, n = matrix.length; i < n; i++) {
for (int j = 0, k = matrix.length; j < k; j++) {
txt.append(" ");
txt.append(matrix[i][j]);
if (j < k-1) {
txt.append(", ");
} else {
txt.append("\n");
}
}
}
System.out.println(txt.toString());
}
public int getSize() {
return matrix.length;
}
public int[] getDangling() {
int n = getSize();
int[] d = new int[n];
boolean foundOne = false;
for (int i=0; i < n; i++) {
for (int j=0; j < n; j++) {
75
if (matrix[i][j] > 0) {
foundOne = true;
break;
}
}
if (foundOne) {
d[i] = 0;
} else {
d[i] = 1;
}
foundOne = false;
}
return d;
}
public ValueToIndexMapping getIndexMapping() {
return indexMapping;
}
}
}
}
MySearcher
package ru.aetet.drillsearcher.searcher;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.FSDirectory;
import ru.aetet.drillsearcher.algos.bayes.Concept;
import ru.aetet.drillsearcher.algos.bayes.bayes.NaiveBayes;
import ru.aetet.drillsearcher.index.clicks.UserClick;
import ru.aetet.drillsearcher.index.clicks.UserQuery;
import ru.aetet.drillsearcher.index.data.SearchResult;
import ru.aetet.drillsearcher.index.ranking.Rank;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
public class MySearcher {
public static final double EPSILON = 0.0001;
private static final String PRETTY_LINE =
"_______________________________________________________________________";
private String indexDir;
76
private NaiveBayes learner = null;
private boolean verbose = true;
public MySearcher(String indexDir) {
this.indexDir = indexDir;
}
public void setUserLearner(NaiveBayes nb) {
learner = nb;
}
public SearchResult[] search(String query, int numberOfMatches) {
SearchResult[] docResults = new SearchResult[0];
IndexSearcher is = null;
try {
is = new IndexSearcher(FSDirectory.getDirectory(indexDir));
} catch (IOException ioX) {
System.out.println("ERROR: "+ioX.getMessage());
}
QueryParser qp = new QueryParser("content", new StandardAnalyzer());
Query q = null;
try {
q = qp.parse(query);
} catch (ParseException pX) {
System.out.println("ERROR: "+pX.getMessage());
}
Hits hits = null;
try {
hits = is.search(q);
int n = Math.min(hits.length(), numberOfMatches);
docResults = new SearchResult[n];
for (int i = 0; i < n; i++) {
docResults[i] = new SearchResult(hits.doc(i).get("docid"),
hits.doc(i).get("doctype"),
hits.doc(i).get("title"),
hits.doc(i).get("url"),
hits.score(i));
}
is.close();
} catch (IOException ioX) {
System.out.println("ERROR: "+ioX.getMessage());
}
77
String header = "Search results using Lucene index scores:";
boolean showTitle = true;
printResults(header, "Query: " + query, docResults, showTitle);
return docResults;
}
public SearchResult[] search(String query, int numberOfMatches, Rank pR) {
SearchResult[] docResults = search(query, numberOfMatches);
String url;
int n = pR.getH().getSize();
double m = 1 - (double) 1/n;
int actualNumberOfMatches = docResults.length;
for (int i = 0; i < actualNumberOfMatches; i++) {
url = docResults[i].getUrl();
double hScore = docResults[i].getScore() * Math.pow(pR.getPageRank(url),m);
docResults[i].setScore(hScore);
}
SearchResult.sortByScore(docResults);
String header = "Search results using combined Lucene scores and page rank scores:";
boolean showTitle = false;
printResults(header, "Query: " + query, docResults, showTitle);
return docResults;
}
public SearchResult[] search(UserQuery uQuery, int numberOfMatches, Rank pR) {
SearchResult[] docResults = search(uQuery.getQuery(), numberOfMatches);
String url;
int docN = docResults.length;
if (docN > 0) {
int loop = (docN<numberOfMatches) ? docN : numberOfMatches;
for (int i = 0; i < loop; i++) {
url = docResults[i].getUrl();
78
UserClick uClick = new UserClick(uQuery,url);
double indexScore
= docResults[i].getScore();
double pageRankScore = pR.getPageRank(url);
double userClickScore = 0.0;
for (Concept bC : learner.getTset().getConceptSet()) {
if (bC.getName().equalsIgnoreCase(url)) {
userClickScore = learner.getProbability(bC, uClick);
}
}
double hScore;
if (userClickScore == 0) {
hScore = indexScore * pageRankScore * EPSILON;
} else {
hScore = indexScore * pageRankScore * userClickScore;
}
docResults[i].setScore(hScore);
}
}
SearchResult.sortByScore(docResults);
String header = "Search results using combined Lucene scores, " +
"page rank scores and user clicks:";
String query = "Query: user=" + uQuery.getUid() + ", query text=" + uQuery.getQuery();
boolean showTitle = false;
printResults(header, query, docResults, showTitle);
return docResults;
}
public boolean isVerbose() {
return verbose;
}
public void setVerbose(boolean verbose) {
this.verbose = verbose;
}
private void printResults(String header, String query, SearchResult[] values, boolean showDocTitle) {
if( verbose ) {
StringWriter sw = new StringWriter();
79
PrintWriter pw = new PrintWriter(sw);
boolean printEntrySeparator = false;
if( showDocTitle ) {
printEntrySeparator = true;
}
pw.print("\n");
pw.println(header);
if( query != null ) {
pw.println(query);
}
pw.print("\n");
for(int i = 0, n = values.length; i < n; i++) {
if( showDocTitle ) {
pw.printf("Document Title: %s\n", values[i].getTitle());
}
pw.printf("Document URL: %-46s --> Relevance Score: %.15f\n",
values[i].getUrl(), values[i].getScore());
if( printEntrySeparator ) {
pw.printf(PRETTY_LINE);
pw.printf("\n");
}
}
if( !printEntrySeparator ) {
pw.print(PRETTY_LINE);
}
System.out.println(sw.toString());
}
}
}
CrawlData
package ru.aetet.drillsearcher.util.crawling.core;
mport ru.aetet.drillsearcher.util.crawling.db.GatheredDocsDB;
import ru.aetet.drillsearcher.util.crawling.db.KnownUrlDB;
import ru.aetet.drillsearcher.util.crawling.db.PageLinkDB;
import ru.aetet.drillsearcher.util.crawling.db.ProcessedDocsDB;
importjava.io.File;
/**
* Важный класс, необходимый для того, чтобы хранить информацию о том, где находятся данные
для сбора информации, и куда попадают его результаты.
*/
public class CrawlData {
/**
* Корень краулера
*/
privateFilecrawlRootDir;
/**
* Место, где хранится добытая информация
80
*/
privateGatheredDocsDBgatheredDocsDB;
/**
* Место, где хранится обрабатываемая информация
*/
privateProcessedDocsDBprocessedDocsDB;
/**
* Место, где хранятся известные урлы добычи информации
*/
privateKnownUrlDBknownUrlsDB;
/**
* Место, где хранятся внешние урлы
*/
private PageLinkDB pageLinkDB;
/**
* @see #crawlRootDir
* @return
*/
public File getCrawlRootDir() {
return crawlRootDir;
}
/**
* @see #knownUrlsDB
* @return
*/
public KnownUrlDB getKnownUrlsDB() {
return knownUrlsDB;
}
/**
* @see #pageLinkDB
* @return
*/
public PageLinkDB getPageLinkDB() {
return pageLinkDB;
}
/**
* @see #gatheredDocsDB
* @return
*/
public GatheredDocsDB getGatheredDocsDB() {
return gatheredDocsDB;
}
/**
* @see #processedDocsDB
* @return
*/
public ProcessedDocsDB getProcessedDocsDB() {
return processedDocsDB;
}
public CrawlData(String rootDir) {
this.crawlRootDir = new File(rootDir);
81
crawlRootDir.mkdirs();
File gatheredDocsDBRoot = new File(crawlRootDir, "gathered");
this.gatheredDocsDB = new GatheredDocsDB(gatheredDocsDBRoot);
File processedDocsDBRoot = new File(crawlRootDir, "processed");
this.processedDocsDB = new ProcessedDocsDB(processedDocsDBRoot);
File knownUrlsDBRoot = new File(crawlRootDir, "knownurls");
this.knownUrlsDB = new KnownUrlDB(knownUrlsDBRoot);
File pageLinkDBRoot = new File(crawlRootDir, "pagelinks");
this.pageLinkDB = new PageLinkDB(pageLinkDBRoot);
}
/**
* Подготавливаем хранилище для сбора информации
*/
public void init() {
this.gatheredDocsDB.init();
this.processedDocsDB.init();
this.knownUrlsDB.init();
this.pageLinkDB.init();
}
/**
* Очищаем хранилище информации
*/
public void delete() {
this.gatheredDocsDB.delete();
this.processedDocsDB.delete();
this.knownUrlsDB.delete();
this.pageLinkDB.delete();
}
}
GatherCrawler
package ru.aetet.drillsearcher.util.crawling.impl;
import ru.aetet.drillsearcher.util.crawling.core.BasicWebCrawler;
import ru.aetet.drillsearcher.util.crawling.core.CrawlData;
import ru.aetet.drillsearcher.util.crawling.core.URLFilter;
import ru.aetet.drillsearcher.util.urlnormalizer.URLNormalizer;
import java.util.ArrayList;
import java.util.List;
/**
* User: MGrebenshchikov
* Date: 13.05.12
* Time: 14:32
*/
public class GatherCrawler extends BasicWebCrawler{
/**
* Максимальная глубина просмотра по умолчанию
*/
public static final int DEFAULT_MAX_DEPTH = 3;
82
/**
* Максимальное количество документов за одну итерацию по умолчанию
*/
public static final int DEFAULT_MAX_DOCS = 1000;
/**
* Ссылка на собираемые данные
*/
privateCrawlDatacrawlData;
/**
*Место, где лежит корень оригинального контента
*
*/
private String rootDir;
/**
*Сколько будет итераций
*/
private int maxDepth;
/**
*Сколько страниц будет просмотрено за каждую итерацию
*/
private int maxDocs;
/**
* Ссылки для обхода
*/
private List<String> seedUrls;
/**
* Фильтр для ссылок
*/
private URLFilter urlFilter;
/**
* По умолчанию ходим на http://google.com
* @paramdir Директория, в которой будут лежать результаты обхода.
*/
public GatherCrawler(String dir){
super(dir);
this.rootDir = super.getRootDir();
this.maxDepth = DEFAULT_MAX_DEPTH;
this.maxDocs = DEFAULT_MAX_DOCS;
this.seedUrls = new ArrayList<String>() ;
this.seedUrls.add("http://google.com");
//Дефолтная инициализация фильтра
this.urlFilter = new URLFilter();
urlFilter.setAllowFileUrls(true);
urlFilter.setAllowHttpUrls(true);
83
}
/**
*
*@paramdir Директория, в которой будут лежать результаты обхода.
*@paramseedUrls Первоначальные ссылки для обхода.
*/
public GatherCrawler(String dir, List<String> seedUrls){
super(dir);
this.rootDir = super.getRootDir();
this.crawlData = new CrawlData(rootDir);
this.maxDepth = DEFAULT_MAX_DEPTH;
this.maxDocs = DEFAULT_MAX_DOCS;
this.seedUrls = seedUrls;
//Дефолтная инициализация фильтра
this.urlFilter = new URLFilter();
urlFilter.setAllowFileUrls(true);
urlFilter.setAllowHttpUrls(true);
}
/**
* По умолчанию ходим на http://google.com
* @paramdir Директория, в которой будут лежать результаты обхода.
* @parammaxDepth Максимальная глубина обхода.
* @parammaxDocs Максимальное количество документов для обхода за одну итерацию.
*/
public GatherCrawler(String dir, int maxDepth, int maxDocs){
super(dir);
this.rootDir = super.getRootDir();
this.crawlData = new CrawlData(rootDir);
this.maxDepth = maxDepth;
this.maxDocs = maxDocs;
this.seedUrls = new ArrayList<String>() ;
this.seedUrls.add("http://google.com");
//Дефолтная инициализация фильтра
this.urlFilter = new URLFilter();
urlFilter.setAllowFileUrls(true);
urlFilter.setAllowHttpUrls(true);
}
/**
* @paramdir Директория, в которой будут лежать результаты обхода.
* @parammaxDepth Максимальная глубина обхода.
* @parammaxDocs Максимальное количество документов для обхода за одну итерацию.
* @paramseedUrls Первоначальные ссылки для обхода.
*/
public GatherCrawler(String dir, int maxDepth, int maxDocs, List<String> seedUrls){
super(dir);
this.rootDir = super.getRootDir();
this.crawlData = new CrawlData(rootDir);
this.maxDepth = maxDepth;
this.maxDocs = maxDocs;
84
this.seedUrls = seedUrls;
//Дефолтная инициализация фильтра
this.urlFilter = new URLFilter();
urlFilter.setAllowFileUrls(true);
urlFilter.setAllowHttpUrls(true);
}
/**
* @paramdir Директория, в которой будут лежать результаты обхода.
* @parammaxDepth Максимальная глубина обхода.
* @parammaxDocs Максимальное количество документов для обхода за одну итерацию.
* @paramseedUrls Первоначальные ссылки для обхода.
* @paramurlFilter Фильтр для ссылок, которые будем обходить.
*/
public GatherCrawler(String dir, int maxDepth, int maxDocs, List<String> seedUrls, URLFilter
urlFilter){
super(dir);
this.rootDir = super.getRootDir();
this.crawlData = new CrawlData(rootDir);
this.maxDepth = maxDepth;
this.maxDocs = maxDocs;
this.seedUrls = seedUrls;
//неДефолтная инициализация фильтра :-)
this.urlFilter = urlFilter;
}
/**
* Исходные ссылки для обхода
* @return getSeedUrls
*/
public List<String> getSeedUrls() {
returnseedUrls;
}
/**
* Таким будут наши пути поиска с коллекцией
* @param seedUrls Пути поиска
*/
public void setSeedUrls(List<String> seedUrls){
this.seedUrls = seedUrls;
}
/**
* Ссылку добавляем, чтобы силу Сборщика информации обрести
* @paramval Значение ссылки для сбора информации
*/
public void addUrl(String val) {
URLNormalizer urlNormalizer = new URLNormalizer();
seedUrls.add(urlNormalizer.normalizeUrl(val));
}
/**
*Устанавливаем для ссылок, которые будет перебирать сборщик
* @param urlFilter
85
*/
public void setUrlFilter(URLFilter urlFilter) {
this.urlFilter = urlFilter;
}
/**
*С таким фильтром обрабатываем файлы file:// urls
*/
public void setFilesOnlyUrlFilter() {
URLFilter urlFilter = new URLFilter();
urlFilter.setAllowFileUrls(true);
urlFilter.setAllowHttpUrls(false);
setUrlFilter(urlFilter);
}
/**
* Просматриваем URL начинающихся с http://
*/
publicvoidsetWebOnlyUrlFilter() {
/* С таким фильтром токмо файлы http:// urls */
URLFilter urlFilter = new URLFilter();
urlFilter.setAllowFileUrls(true);
urlFilter.setAllowHttpUrls(false);
setUrlFilter(urlFilter);
}
/**
* rootDir получаем корневую директорию
* @returnrootDir
*/
public String getRootDir() {
return rootDir;
}
public void setRootDir(String rootDir) {
this.rootDir = rootDir;
}
/**
* Глубина нашего поиска
* @return maxNumberOfCrawls
*/
public int getMaxNumberOfCrawls() {
return maxDepth;
}
/**
* Устанавливаемглубинупоиска
* @param maxNumberOfCrawls
*/
public void setMaxNumberOfCrawls(int maxNumberOfCrawls) {
this.maxDepth = maxNumberOfCrawls;
}
/**
* Сколько документов за один цикл сборщика информации
86
* @return maxNumberOfDocsPerCrawl
*/
public int getMaxNumberOfDocsPerCrawl() {
returnmaxDocs;
}
/**
* Хотим, чтобы за каждый цикл мы смотрели только это кол-во документов
* @param maxNumberOfDocsPerCrawl
*/
public void setMaxNumberOfDocsPerCrawl(int maxNumberOfDocsPerCrawl) {
this.maxDocs = maxNumberOfDocsPerCrawl;
}
/**
* Данные для сборщика информации
* @return crawlData
*/
public CrawlData getCrawlData() {
returncrawlData;
}
/**
* Запускаем сборщика информации
*/
public void run(){
this.addSeedUrls(getSeedUrls());
this.setURLFilter(urlFilter);
long t0 = System.currentTimeMillis();
/* run crawl */
this.gatherAndProcess(maxDepth, maxDocs);
this.crawlData = super.getCrawlData();
System.out.println("Timer (s): [Crawler processed data] --> " +
(System.currentTimeMillis()-t0)*0.001);
}
}
HTTPTransport
package ru.aetet.drillsearcher.util.crawling.transport.http;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import ru.aetet.drillsearcher.util.crawling.model.GatheredDocument;
import ru.aetet.drillsearcher.util.crawling.transport.common.Transport;
import ru.aetet.drillsearcher.util.crawling.transport.common.TransportException;
import java.io.IOException;
import java.util.HashMap;
/**
87
* Класс для работы с http протоколом передачи информации
*/
public class HTTPTransport implements Transport {
HttpState initialState = null;
HttpClient httpclient = null;
public HTTPTransport() {
}
/**
* Инициализируем http протокол.Устанавливаем Timeout. httpClient, httpState используя
библиотеку commonsHttp
*/
public void init() {
System.out.println("Initializing HTTPTransport ...");
initialState = new HttpState();
httpclient = new HttpClient();
httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);
httpclient.getHttpConnectionManager().getParams().setSoTimeout(30000);
httpclient.setState(initialState);
httpclient.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);
httpclient.getParams().setParameter(
HttpClientParams.ALLOW_CIRCULAR_REDIRECTS, Boolean.TRUE);
// Set default number of connections per host to 1
getParams().setMaxConnectionsPerHost(
HostConfiguration.ANY_HOST_CONFIGURATION, 1);
httpclient.getHttpConnectionManager().getParams().setMaxTotalConnections(10);
}
/** Очищаем состояние
*
*/
public void clear() {
httpclient = null;
initialState = null;
}
public GatheredDocument gather(String documentUrl)
throws TransportException {
GetMethod httpget = null;
GatheredDocument doc = null;
try {
httpget = new GetMethod(documentUrl);
httpget.setFollowRedirects(true);
int result = httpclient.executeMethod(httpget);
if( result != 200) {
String errorMessage = "HTTP Response code: " + result +
", status text: " + httpget.getStatusText() +
" for url: '" + documentUrl + "'.";
throw new TransportException(errorMessage);
}
else {
doc = createDocument(documentUrl, httpget);
88
}
}
catch(IOException e) {
throw new TransportException("Failed to gather url: '" + documentUrl + "': ", e);
}
finally {
if( httpget != null ) {
httpget.releaseConnection();
}
}
return doc;
}
private GatheredDocument createDocument(String targetURL, GetMethod httpget)
throws IOException, HTTPTransportException {
GatheredDocument doc = new GatheredDocument();
int MAX_DOCUMENT_LENGTH = 1500 * 1024; // 512K
/* IOException will be thrown for documents that exceed max length */
byte[] data = httpget.getResponseBody(MAX_DOCUMENT_LENGTH);
Header contentEncodingHeader = httpget.getResponseHeader("Content-Encoding");
if( contentEncodingHeader != null ) {
data = HTTPUtils.decodeContent(contentEncodingHeader.getValue(), data);
}
/* 'Content-Type' HTTP header value */
String contentTypeHeaderValue = null;
Header header = httpget.getResponseHeader("Content-Type");
if( header != null ) {
contentTypeHeaderValue = header.getValue();
}
String DEFAULT_CONTENT_TYPE = "text/html";
String contentType = HTTPUtils.getContentType(contentTypeHeaderValue, targetURL, data);
if( contentType == null ) {
contentType = DEFAULT_CONTENT_TYPE;
}
String DEFAULT_CONTENT_CHARSET = "UTF-8";
String contentCharset = HTTPUtils.getCharset(contentTypeHeaderValue, contentType, data);
if( contentCharset == null ) {
contentCharset = DEFAULT_CONTENT_CHARSET;
}
doc.setContentType(contentType);
doc.setDocumentURL(targetURL);
doc.setContentCharset(contentCharset);
doc.setDocumentContent(data);
doc.setDocumentMetadata(new HashMap<String, String>());
return doc;
}
public boolean pauseRequired() {
return true;
89
}
}
90
Download