Я задал simlar вопрос о переполнении Meta Stack, но это касается только того, есть ли Lucene.NET используется в Stack Overflow.
Цель вопроса здесь более гипотетическая, относительно того, какие подходы можно было бы сделать, если бы они использовали Lucene.NET в качестве основы для поиска на месте и других факторов на сайте, таком как Qaru [SO ].
Согласно записи в блоге Qaru под названием "Проблемы полнотекстового поиска SQL 2008, было указано strong, что Lucene.NET рассматривался в какой-то момент, но похоже, что это определенно не так, согласно замечанию Джеффа Далгаса от 19 февраля 2010 года:
Lucene.NET не используется для Stack Переполнение - мы используем SQL Server Полное текстовое индексирование. Поиск - это область где мы продолжаем делать незначительные щипки.
Итак, мой вопрос: как использовать Lucene.NET на сайте, который имеет ту же семантику Stack Overflow?
Вот какой-то фон и то, что я сделал/думал до сих пор (да, я реализовал большую часть этого, и поиск - последний аспект, который я должен выполнить):
Технологии:
И, конечно, звезда шоу, Lucene.NET.
Целью также является переход на .NET/С# 4.0 как можно скорее. Следует отметить, что, хотя я не думаю, что это игровой чейнджер.
Прежде чем перейти к аспектам Lucene.NET, важно указать на него аспекты SQL Server 2008, а также на модели.
Модели
Эта система имеет более одного типа первичной модели по сравнению с Stack Overflow. Некоторые примеры этих моделей:
- Вопросы: Это вопросы, которые люди могут задать. Люди могут отвечать на вопросы, точно так же, как на Stack Overflow.
- Примечания. Это односторонние прогнозы, поэтому, в отличие от вопроса, вы делаете выражение о контенте. Люди не могут публиковать ответы на это.
- События. Это данные о событии реального времени. Он содержит информацию о местоположении, информацию о дате/времени.
Важно отметить эти модели:
- Все они имеют свойство Name/Title (текст) и свойство Body (HTML) (форматы неактуальны, так как контент будет анализироваться соответствующим образом для анализа).
- Каждый экземпляр модели имеет уникальный URL-адрес на сайте
Тогда есть вещи, которые Qaru предоставляет, которые IMO, являются декораторами для моделей. Эти декораторы могут иметь разную мощность, либо быть один-к-одному, либо один-ко-многим:
- Голоса: Ключ от пользователя
- Ответы: Дополнительно, в качестве примера, см. приведенный выше примечание.
- Избранные: Является ли модель указанной в качестве фаворита пользователя?
- Комментарии: (необязательно)
- Ассоциации тегов: теги находятся в отдельной таблице, чтобы не копировать тег для каждой модели. Существует связь между моделью и таблицей ассоциаций тегов, а затем из таблицы ассоциаций тегов в таблицу тегов.
И есть поддерживающие подсчеты, которые сами по себе являются индивидуальными декораторами для моделей, которые привязаны к ним одинаково (обычно по типу идентификатора модели и идентификатору модели):
- Голосовые подсчеты: Всего постов, отрицательных голосов, Интервал Wilson Score (это важно, он будет определять уровень достоверности на основе голосов для записи, по большей части, принимают нижнюю границу интервала Вильсона).
Ответы (ответы) - это модели, которые имеют большинство декораторов, которые есть у большинства моделей, у них просто нет названия или URL-адреса, и вопрос о том, является ли модель ответом, является необязательным. Если ответы разрешены, это, конечно, отношение "один ко многим".
SQL Server 2008
Таблицы в значительной степени соответствуют расположению моделей выше, с отдельными таблицами для декораторов, а также некоторыми поддерживающими таблицами и представлениями, хранимыми процедурами и т.д.
Следует отметить, что решение не использовать полнотекстовый поиск основывается главным образом на том, что он не нормализует такие оценки, как Lucene.NET. Я открыт для предложений о том, как использовать текстовый поиск, но мне придется выполнять поиск по нескольким типам моделей, поэтому имейте в виду, что мне нужно как-то нормализовать счет.
Lucene.NET
Вот где большой знак вопроса. Вот мои мысли до сих пор о функциональных возможностях Stack Overflow, а также о том, как и что я уже сделал.
Индексация
Вопросы/Модели
Я считаю, что каждая модель должна иметь собственный индекс, содержащий уникальный идентификатор, чтобы быстро найти его на основе экземпляра Term этого идентификатора (индексированного, не проанализированного).
В этой области я рассмотрел, что Lucene.NET анализирует каждый вопрос/модель и каждый ответ индивидуально. Поэтому, если бы был один вопрос и пять ответов, вопрос и каждый из ответов были бы проиндексированы как одна единица отдельно.
Идея здесь в том, что оценка релевантности, которую возвращает Lucene.NET, будет легче сравнивать между моделями, которые проектируются по-разному (скажем, что-то без ответов).
В качестве примера задается вопрос, а затем ответ подробно обсуждается.
Для заметки, которая не имеет ответов, она обрабатывает вопрос о представлении предмета и затем разрабатывает его.
Я считаю, что это поможет сделать оценки релевантности более релевантными друг другу.
Метки
Вначале я думал, что они должны храниться в отдельном индексе с несколькими полями, которые имеют идентификаторы документов в соответствующем индексе модели. Или, если это слишком велико, есть индекс с только тегами и другим индексом, который поддерживает связь между индексом тегов и вопросами, к которым они применяются. Таким образом, когда вы нажимаете на тег (или используете структуру URL), легко видеть прогрессивным образом, что вам нужно только "купить", если вам удастся:
- Если тег существует
- Какие вопросы связаны с тегами
- Сами вопросы
Однако на практике выполнение запроса всех элементов на основе тегов (например, щелчка по тегу в Stack Overflow) очень просто с 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 для заказа на основе интервала оценки Wilson следующим образом:
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
Похоже, что это простой способ использовать эту функцию для обработки элемента Qaru "получить все элементы, помеченные тегом <tag> ".
Ответы
Первоначально я думал, что это отдельный индекс, с ключом обратно в индекс "Вопросы".
Я думаю, что должна быть комбинация каждой модели и каждого ответа (если таковая имеется), так что оценки релевантности в разных моделях более "равны" по сравнению друг с другом.
Это, конечно, раздуло бы индекс. Я сейчас немного доволен этим.
Или, есть способ сохранить, скажем, модели и ответы как отдельные документы в Lucene.NET, а затем взять оба и уметь получить оценку релевантности для запроса, рассматривающего оба документа как один? Если это так, тогда это будет ideal.
Конечно, вопрос о том, какие поля будут храниться, индексироваться, анализироваться (все операции могут быть отдельными операциями или смешанными и сопоставляемыми)? Сколько будет индексировать?
Как насчет использования специальных стволовых/носителей для орфографических ошибок (с использованием Metaphone), а также синонимов (есть терминология в сообществе, которое я буду обслуживать, у которого есть собственный сленг/терминология для определенных вещей, которые имеют множественные представления)?
подталкивания
Это связано, конечно, с индексированием, но я считаю, что это заслуживает его собственного раздела.
Вы увеличиваете поля и/или документы? Если да, то как вы их повышаете? Является ли константа форсирования для определенных полей? Или он пересчитывается для полей, в которых применимы данные голосования/просмотра/любимые/внешние данные.
Например, в документе заголовок получает повышение над телом? Если да, то какие факторы формовки, по вашему мнению, работают хорошо? Как насчет тегов?
Мысль здесь такая же, как и по строкам Stack Overflow. Термины в документе имеют релевантность, но если документ помечен термином или он находится в заголовке, то он должен быть повышен.
Shashikant Kore предлагает такую структуру документа, как это:
- Название
- Вопрос
- Принятый ответ (или очень проголосовавший ответ, если нет принятого ответа)
- Все ответы объединены
И затем с помощью boost, но не на основе исходного значения. Я считаю, что у меня есть тот, который покрыт интервалом времени Уилсона.
Вопрос в том, следует ли применять всплеск ко всему документу? Я склоняюсь к этому нет, потому что это означало бы, что мне придется переиндексировать документ каждый раз, когда пользователь проголосовал бы за модель.
Поиск тегов
Первоначально я думал, что при запросе на тег (путем отдельного нажатия на один или с использованием структуры 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 (вместе с идентификаторами элементов, которые нужно выбрать), после чего я выполнил вычисление с оценкой достоверности и затем вернул данные правильно.
Как уже было сказано, есть много других вопросов, которые у меня есть об этом, и ответы начали создавать вещи и будут продолжать расширяться по мере того, как вопрос и ответы будут рассмотрены.