Я задал простой вопрос о переполнении стека , но это конкретно касается того, используется ли Lucene.NET при переполнении стека.
Цель вопроса здесь скорее гипотетическая, относительно того, какие подходы можно было бы использовать, если бы они использовали Lucene.NET в качестве основы для поиска по сайту и других факторов на сайте , таких как Переполнение стека [SO].
Согласно записи в блоге Stack Overflow, озаглавленной " Проблемы полнотекстового поиска в SQL 2008 ", было сильное указание на то, что в какой-то момент рассматривался Lucene.NET, но, похоже, это не совсем так, согласно комментарию Джеффа Далгаза от 19 февраля 2010 года:
Lucene.NET не используется для стека
Переполнение - мы используем SQL Server
Полнотекстовая индексация. Поиск это область
где мы продолжаем делать второстепенные
щипки.
Итак, мой вопрос: как использовать Lucene.NET на сайте с такой же семантикой переполнения стека?
Вот некоторая предыстория и то, что я уже сделал / подумал (да, я реализовал большую часть этого, и поиск - последний аспект, который я должен завершить):
Технологии:
И, конечно, звезда шоу, Lucene.NET.
Также планируется перейти на .NET / C # 4.0 как можно скорее. Хотя я не думаю, что это изменит правила игры, это следует отметить.
Прежде чем углубляться в аспекты Lucene.NET, важно указать на его аспекты в SQL Server 2008, а также на соответствующие модели.
Модель
Эта система имеет более одного основного типа модели по сравнению с переполнением стека. Некоторые примеры этих моделей:
- Вопросы: это вопросы, которые люди могут задавать. Люди могут отвечать на вопросы, как и в случае переполнения стека.
- Примечания. Это односторонние проекции, поэтому в отличие от вопроса вы делаете заявление о содержании. Люди не могут оставлять ответы на это.
- События: это данные о событии в реальном времени. Имеется информация о местоположении, дате и времени.
Важное замечание по поводу этих моделей:
- Все они имеют свойство Name / Title (текст) и свойство Body (HTML) (форматы не имеют значения, так как контент будет анализироваться соответствующим образом для анализа).
- Каждый экземпляр модели имеет уникальный URL на сайте
Тогда есть вещи, которые обеспечивает переполнение стека, которые IMO являются декораторами для моделей. Эти декораторы могут иметь разный кардинал, один к одному или один ко многим:
- Голосов: набрано у пользователя
- Ответы: Необязательно, в качестве примера, см. Выше заметки
- Избранное: модель указана в списке избранных пользователя?
- Комментарии: (необязательно)
- Ассоциации тегов: теги находятся в отдельной таблице, чтобы не повторять тег для каждой модели. Существует связь между моделью и таблицей ассоциаций тегов, а затем из таблицы ассоциаций тегов в таблицу тегов.
И есть опорные бюллетени, которые сами по себе являются декораторами «один к одному» для моделей, которые привязаны к ним одинаково (обычно по типу идентификатора модели и идентификатору модели):
- Подсчет голосов: общее количество положительных, отрицательных голосов, Интервал оценки Уилсона (это важно, он будет определять уровень доверия на основе голосов за запись, по большей части, принять нижнюю границу интервал Вильсона).
Ответы (ответы) - это модели, у которых есть большинство декораторов, которые есть у большинства моделей, у них просто нет заголовка или URL-адреса, и указывать, есть ли у модели ответ, необязательно. Если ответы разрешены, это, конечно, отношение один ко многим.
SQL Server 2008
Таблицы в основном соответствуют макету моделей, приведенных выше, с отдельными таблицами для декораторов, а также с некоторыми вспомогательными таблицами и представлениями, хранимыми процедурами и т. Д.
Следует отметить, что решение не использовать полнотекстовый поиск основано, прежде всего, на том факте, что он не нормализует оценки, такие как Lucene.NET. Я открыт для предложений о том, как использовать текстовый поиск, но мне придется выполнять поиск по нескольким типам моделей, поэтому имейте в виду, что мне нужно нормализовать оценку как-то .
Lucene.NET
Это где большой знак вопроса. Вот мои мысли о функциональности переполнения стека, а также о том, как и что я уже сделал.
Индексация
Вопросы / Модели
Я полагаю, что каждая модель должна иметь собственный индекс, содержащий уникальный идентификатор, чтобы быстро искать его на основе экземпляра Term этого идентификатора (проиндексированного, не проанализированного).
В этой области я рассмотрел вопрос о том, чтобы Lucene.NET анализировал каждый вопрос / модель и каждый ответ отдельно. Таким образом, если бы был один вопрос и пять ответов, вопрос и каждый из ответов были бы проиндексированы как одна единица отдельно.
Идея состоит в том, что показатель релевантности, который возвращает Lucene.NET, будет легче сравнивать между моделями, которые проецируют по-разному (скажем, что-то без ответов).
Например, вопрос задает тему, а затем уточняется ответ.
Для заметки, которая не имеет ответов, она решает вопрос представления предмета, а затем развивает его.
Я считаю, что это поможет сделать оценки релевантности более релевантными друг другу.
Метки
Первоначально я думал, что они должны храниться в отдельном индексе с несколькими полями, которые имеют идентификаторы документов в соответствующем модельном индексе. Или, если он слишком большой, существует индекс, содержащий только теги, и другой индекс, который поддерживает связь между индексом тегов и вопросами, к которым они применяются. Таким образом, когда вы нажимаете на тег (или используете структуру URL), легко увидеть прогрессивную манеру, которую вам нужно только «купить» в случае успеха:
- Если тег существует
- С какими вопросами связаны теги
- Сами вопросы
Однако на практике выполнение запроса всех элементов на основе тегов (например, щелчка по тегу в переполнении стека) чрезвычайно просто с SQL Server 2008. На основе приведенной выше модели просто требуется запрос, такой как:
select
m.Name, m.Body
from
Models as m
left outer join TagAssociations as ta on
ta.ModelTypeId = <fixed model type id> and
ta.ModelId = m.Id
left outer join Tags as t on t.Id = ta.TagId
where
t.Name = <tag>
И поскольку определенные свойства являются общими для всех моделей, достаточно просто сделать UNION
между различными типами / таблицами моделей и получить согласованный набор результатов.
Это было бы аналогично TermQuery
в Lucene.NET (я ссылаюсь на документацию по Java , поскольку она всеобъемлющая, а Lucene.NET должен быть строкой построчный перевод Lucene , поэтому вся документация одинакова).
Проблема, возникающая при использовании Lucene.NET, связана с порядком сортировки. Оценка релевантности для TermQuery, когда дело доходит до тегов, не имеет значения. Это либо 1, либо 0 (есть или нет).
В этот момент для упорядочения результатов вступает в игру показатель достоверности (интервал оценок Уилсона).
Эта оценка может храниться в Lucene.NET, но для сортировки результатов в этом поле она будет полагаться на значения, хранящиеся в кэше полей, чего я действительно очень хочу избежать. Для большого количества документов кэш поля может стать очень большим (счет Уилсона удваивается, и вам потребуется один дубль для каждого документа, который может быть одним большим массивом).
Учитывая, что я могу изменить инструкцию SQL на порядок, основанный на интервале оценок Уилсона, как это:
select
m.Name, m.Body
from
Models as m
left outer join TagAssociations as ta on
ta.ModelTypeId = <fixed model type id> and
ta.ModelId = m.Id
left outer join Tags as t on t.Id = ta.TagId
left outer join VoteTallyStatistics as s on
s.ModelTypeId = ta.ModelTypeId and
s.ModelId = ta.ModelId
where
t.Name = <tag>
order by
--- Use Id to break ties.
s.WilsonIntervalLowerBound desc, m.Id
Кажется, что это простой выбор для обработки части функции переполнения стека "пометить все элементы с помощью ".
Ответов
Первоначально я думал, что это отдельный отдельный индекс с ключом обратно в индекс вопросов.
Я думаю, что должна быть комбинация каждой модели и каждого ответа (если таковая имеется), чтобы оценки релевантности для разных моделей были более "равными" по сравнению друг с другом.
Это, конечно, увеличило бы индекс. Сейчас мне это немного комфортно.
Или есть способ сохранить, скажем, модели и ответы как отдельные документы в Lucene.NET, а затем взять оба и получить оценку релевантности для запроса, рассматривая оба документа как один ? Если это так, то это будет идеально .
Конечно, возникает вопрос о том, какие поля будут храниться, индексироваться, анализироваться (все операции могут быть отдельными операциями или смешивать и сопоставлять)? Сколько будет один индекс?
А как насчет использования специальных расширителей / носильщиков для орфографических ошибок (с помощью Метафона), а также синонимов (в сообществе, которое я буду обслуживать, есть своя терминология, которая имеет свой собственный сленг / терминологию для определенных вещей, которая имеет несколько представлений)
Повышение
Конечно, это связано с индексацией, но я думаю, что она заслуживает отдельного раздела.
Вы повышаете поля и / или документы? Если так, как вы их повысите? Является ли усиление постоянным для определенных полей? Или же он пересчитывается для полей, где применимо голосование / просмотр / избранные / внешние данные.
Например, в документе заголовок получает усиление над телом? Если да, то какие факторы повышения, по вашему мнению, работают хорошо? А как насчет тегов?
Мышление здесь такое же, как и в случае переполнения стека. Термины в документе имеют значение, но если документ помечен термином или в заголовке, его следует увеличить.
Shashikant Kore предлагает такую структуру документа:
- Название
- Вопрос
- Принятый ответ (или ответ с высоким рейтингом, если нет принятого ответа)
- Все ответы объединены
И затем с использованием повышения, но не на основе необработанного значения голоса. Я полагаю, что это покрыто интервалом счета Уилсона.
Вопрос в том, должно ли повышение применяться ко всему документу? Я склоняюсь к «нет», потому что это будет означать, что мне придется переиндексировать документ каждый раз, когда пользователь голосует по модели.
Поиск предметов с меткой
Первоначально я думал, что при запросе тега (путем особого нажатия на него или использования структуры URL для поиска содержимого с тегами) это простой TermQuery для индекса тега для тега, а затем в индексе ассоциаций (если необходимо ) затем вернемся к вопросам, Lucene.NET справится с этим очень быстро.
Однако, учитывая приведенные выше замечания относительно того, как легко это сделать в SQL Server, я выбрал этот маршрут, когда речь идет о поиске теговых элементов.
Общий поиск
Итак, сейчас самый важный вопрос заключается в том, что при выполнении общего поиска по фразе или термину по контенту, что и как вы интегрируете в другую информацию (например, голоса), чтобы определить результаты в правильном порядке? Например, при выполнении этого поиска в ASP.NET MVC в переполнении стека эти цифры подсчитываются для пяти лучших результатов (при использовании вкладки релевантности):
q votes answers accepted answer votes asp.net highlights mvc highlights
------- ------- --------------------- ------------------ --------------
21 26 51 2 2
58 23 70 2 5
29 24 40 3 4
37 15 25 1 2
59 23 47 2 2
Обратите внимание, что основные моменты присутствуют только в заголовке и аннотации на странице результатов и являются лишь второстепенными показателями относительно того, какова истинная частота термина в документе, заголовке, теге, ответе (однако они применяются, что является еще одним хорошим вопрос).
Как все это объединено?
На данный момент я знаю, что Lucene.NET вернет нормализованную оценку релевантности, а данные голосования дадут мне интервал оценки Уилсона, который я могу использовать для определения степени достоверности.
Как мне смотреть на объединение этих двух баллов, чтобы указать порядок сортировки набора результатов, основанный на релевантности и достоверности?
Для меня очевидно, что между ними должны быть некоторые отношения, но то, какими должны быть эти отношения, уклоняется от меня на данном этапе. Я знаю, что с течением времени я должен уточнить это, но я действительно потерян в этой части.
Мои первоначальные мысли таковы: если показатель релевантности составляет от 0 до 1, а показатель достоверности - от 0 до 1, тогда я мог бы сделать что-то вроде этого:
1 / ((e ^ cs) * (e ^ rs))
Таким образом, можно получить нормализованное значение, которое приближается к 0, тем более релевантным и уверенным является результат, и его можно отсортировать по этому.
Основная проблема заключается в том, что если повышение выполняется для тега и / или поля заголовка, тогда показатель релевантности выходит за границы от 0 до 1 (верхний предел становится неограниченным, и я не знаю, как справиться с этим).
Кроме того, я считаю, что мне придется скорректировать показатель доверия, чтобы учесть подсчеты голосов, которые являются абсолютно отрицательными. Поскольку результаты голосования, которые являются абсолютно отрицательными, дают результат в интервале оценок Уилсона с нижней границей 0, то показатель с -500 голосами имеет тот же показатель достоверности, что и показатель с -1 голосом или 0 голосами.
К счастью, верхняя граница уменьшается с 1 до 0 по мере увеличения числа отрицательных голосов. Я могу изменить показатель достоверности на диапазон от -1 до 1, например:
confidence score = votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound
Проблема с этим заключается в том, что включение 0 в уравнение оценивает все элементы с нулевым голосом ниже, чем с отрицательным подсчетом голосов.
С этой целью я думаю, что если показатель доверия будет использоваться в ответном уравнении, как описано выше (очевидно, я обеспокоен переполнением), то его необходимо переработать, чтобы он всегда был положительным. Один из способов достижения этого:
confidence score = 0.5 +
(votetally < 0 ?
-(1 - wilson score interval upper bound) :
wilson score interval lower bound) / 2
Другие мои вопросы касаются того, как на самом деле выполнять вычисления с учетом Lucene.NET и SQL Server. Я не решаюсь поставить показатель достоверности в индекс Lucene, потому что он требует использования кеша полей, что может оказать огромное влияние на потребление памяти (как упоминалось ранее).
У меня была идея получить оценку релевантности из Lucene.NET, а затем использовать табличный параметр для потоковой передачи оценки в SQL Server (вместе с идентификаторами элементов для выбора), в этот момент я выполнил бы расчет с доверительной оценкой, а затем вернул данные правильно.
Как указывалось ранее, у меня есть много других вопросов по этому поводу, и ответы начали формировать вещи, и будут продолжать расширяться по мере того, как вопрос и ответы эволюционировали.