Движок приложения - простой текстовый поиск - PullRequest
0 голосов
/ 11 октября 2010

Я надеялся реализовать простой, но эффективный текстовый поиск для App Engine, который мог бы использовать до тех пор, пока не будут выпущены официальные возможности текстового поиска для механизма приложений. Я вижу, что есть библиотеки, но всегда сложно установить что-то новое. Мне интересно, если это правильная стратегия:

1) Разбейте каждое свойство, которое должно быть доступно для поиска по тексту, на набор (список) текстовых фрагментов. 2) Сохранить запись с добавлением этих списков 3) При поиске просто используйте фильтры равенства в свойствах списка

Например, если у меня была запись:

{
  firstName="Jon";
  lastName="Doe";
}

Я мог бы сохранить свойство как это:

{
  firstName="Jon";
  lastName="Doe";

  // not case sensative:
  firstNameSearchable=["j","o", "n","jo","on","jon"];   
  lastNameSerachable=["D","o","e","do","oe","doe"];
}

Тогда для поиска я мог бы сделать это и ожидать, что он вернет вышеупомянутую запись:

//pseudo-code:
SELECT person 
WHERE firstNameSearchable=="jo" AND
      lastNameSearchable=="oe"

Так ли реализован текстовый поиск? Как вы удерживаете индекс от выхода из-под контроля, особенно если у вас есть параграф или что-то? Есть ли какая-то другая стратегия сжатия, которая обычно используется? Полагаю, если я просто хочу что-то простое, это может сработать, но приятно знать о проблемах, с которыми я могу столкнуться.

Обновление :::

Хорошо, так получается, что эта концепция, вероятно, законна. Это сообщение в блоге также относится к этому: http://googleappengine.blogspot.com/2010/04/making-your-app-searchable-using-self.html

Примечание: исходный код в сообщении блога выше не работает с текущей версией Lucene. Я установил старую версию (2.9.3) в качестве быстрого исправления, так как в любом случае Google должен в скором времени выпустить собственный текстовый поиск для движка приложения.

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

db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2", "abc", u"abc" + u"\ufffd")

Если вы хотите сделать запрос по нескольким свойствам, вы можете сохранить индексы для каждого свойства. В моем случае я использую это для некоторых функций автоматического предложения в небольших текстовых полях, а не для поиска совпадений слов и фраз в документе (для этого вы можете использовать приведенную выше реализацию блога). Оказывается, это довольно просто, и мне не нужна библиотека для этого. Кроме того, я ожидаю, что если кто-то ищет «Ларри», они начнут набирать «La ...», а не начинать с середины слова: «arry». Таким образом, если свойство предназначено для имени человека или чего-то подобного, индекс имеет только подстроки, начинающиеся с первой буквы, поэтому индекс для "Larry" будет просто {"l", "la", "lar", "larr "," Ларри "}

Я сделал что-то другое для данных, таких как номера телефонов, где вы можете искать их, начиная с начальной или средней цифры. В этом случае я просто сохранил весь набор подстрок, начиная со строк длины 3, поэтому номер телефона "123-456-7890" будет: {"123", "234", "345", .... . "123456789", "234567890", "1234567890"}, всего (10 * ((10 + 1) / 2)) - (10 + 9) = 41 индекс ... на самом деле то, что я сделал, было немного больше сложный, чтобы удалить некоторые маловероятно используемые подстроки, но вы поняли идею.

Тогда ваш запрос будет: (Код псевдо) ВЫБЕРИТЕ * от человека ГДЕ firstNameSearchIndex == "lar" phonenumberSearchIndex == "1234"

Механизм приложения работает так: если подстроки запроса соответствуют какой-либо из подстрок в свойстве, это считается как совпадение.

1 Ответ

2 голосов
/ 11 октября 2010

На практике это не масштабируется. Для строки из n символов вам нужно n записей факторного индекса. Строка из 500 символов потребует 1,2 * 10 ^ 1134 индексов для захвата всех возможных подстрок. Вы умрете от старости до того, как ваша сущность закончит запись в хранилище данных.

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

С Документы :

db.GqlQuery ("ВЫБРАТЬ * ИЗ MyModel" ГДЕ проп> =: 1 И проп <: 2 ", "abc", u "abc" + u "\ ufffd") </p>

Это соответствует каждому объекту MyModel с реквизит свойства строки, начинающийся с символами abc. Юникод Строка u "\ ufffd" представляет максимально возможный символ Unicode. Когда значения свойств отсортированы в индекс, значения, которые попадают в этот диапазон - все значения, которые начинаются с заданным префиксом.

...