Объединение текстового поиска и фильтров запросов в GAE

Я пишу приложение на основе GAE, которое должно позволять пользователям фильтровать элементы по нескольким их свойствам. Элементы хранятся как объекты NDB. Некоторым реквизитам можно сопоставить стандартные фильтры запросов, но для некоторых требуется «полный» (подстрочный) текстовый поиск, чтобы все это имело смысл. Кроме того, требуется разумный порядок. Возможно, лучше всего это проиллюстрировано следующим надуманным примером:

class Product(ndb.Model) :
  manufacturer = ndb.StringProperty()
  model = ndb.StringProperty()
  rating = ndb.IntegerProperty(choices = [1, 2, 3, 4])
  features = ndb.StringProperty(repeated = True, choices = ['feature_1', 'feature_2'])
  is_very_expensive = ndb.BooleanProperty()
  categories = ndb.KeyProperty(kind = Category, repeated = True)

Все сущности продукта имеют того же предка, что и их «контейнер». Товар может принадлежать к одной или нескольким категориям, а последние образуют дерево.

Теперь пользователи должны иметь возможность:

  • Сузьте список продуктов, выбрав категорию (достаточно одной)
  • Отфильтруйте их, указав минимальный рейтинг и желаемые функции.
  • Просмотреть исключительно товары, которые очень дорогие или те, которые не очень (или просмотреть все)
  • Поиск товаров по фрагменту текста из полей модели и/или производителя
  • Заказывайте окончательный список, например. по названию модели (возможность выбрать заказ была бы идеальной).

Все это одновременно, т.е. фильтры и упорядочивание должны беспрепятственно применяться при предоставлении условий поиска.

Вопрос в следующем: как реализовать такую ​​функциональность с помощью GAE?

В базе данных будут сотни тысяч или, возможно, миллионы товаров. Проблема с API поиска при использовании вместе с запросами NDB заключается в фильтрации результатов поиска и, возможно, их упорядочении.

Два решения, о которых я думал:

  1. Добавьте повторяющееся StringProperty в модель Product, которая будет содержать все доступные для поиска подстроки (или, по крайней мере, префиксы) слов из полей manufacturer и model. Это просто и работает, но я серьезно обеспокоен производительностью. В моих экспериментах я получал в среднем 40-50 доступных для поиска префиксов слов для каждого "Product".

  2. Используйте Search API исключительно для этой задачи, применяя расширенные поисковые запросы. Например. я могу хранить категории продуктов (в виде идентификаторов или путей) в отдельном поле документа и использовать это поле для получения продуктов, принадлежащих к данной категории. Вероятно, это можно сделать, но меня здесь беспокоит ограничение в 10 000 результатов поиска и различные ограничения / квоты использования. Я также не уверен в порядке результатов.

Есть ли другие способы?


person hauru    schedule 15.03.2014    source источник
comment
Поиск единого фрагмента текста или комбинаций? Почему у вас есть проблемы с производительностью для решения-1.   -  person voscausa    schedule 15.03.2014
comment
Это решение означает проверку появления каждого поискового слова в повторяющемся свойстве StringProperty для каждого элемента. Я просто не уверен, насколько хорошо Google индексирует такие свойства, особенно когда они довольно длинные. В конце концов, считается, что такой поиск лучше всего выполнять с помощью Search API, а не NDB.   -  person hauru    schedule 15.03.2014
comment
Из документов. Для каждого значения создается отдельная индексная запись.   -  person voscausa    schedule 15.03.2014


Ответы (1)


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

Вот причины, по которым GAE не подходит:

  1. Вы очень быстро столкнетесь со случаями взрыва индекса или иным образом, возможно, рискуете серьезно снизить производительность из-за зигзагообразных запросов, если используете NDB. В этой статье делается попытка обосновать ваши действия, но на практике мы Я обнаружил, что он не подходит для моей повседневной работы, кроме небольших наборов данных/несколько полей. Чем больше упорядоченности вы введете с помощью других фильтров, тем больше проблем это доставит вам, не говоря уже о том, что вам понадобятся множественные неравенства с сортировками.

  2. Полнотекстовый поиск GAE медленный и ограниченный по сравнению с другими предложениями. Сам язык запросов не такой зрелый и гибкий IMO. Это также не очень выгодно по цене/квоте. Вы упомянули, что беспокоитесь о квотах, и поиск легко их проедает.

  3. Метод подстроки увеличивает размер каждой сохраняемой записи. Django non-rel имеет пакет индексатора делает именно это, и это некрасиво. Не уверен, что вы используете Django, но в любом случае вы можете адаптировать код, так как он с открытым исходным кодом. Увеличение размера записи — это плохо, потому что, если вы не используете только проекционные запросы или ключи, вы будете отправлять много ненужных данных по сети.

Вместо этого я рекомендую вам отправлять данные в хранилище данных, которое более оптимизировано для таких запросов. Вот пример схемы архитектуры:

  • Поисковый сервер в Google Compute Engine для уменьшения задержки с помощью App Engine. Не уверен, есть ли способ разместить вещи в одном и том же географическом местоположении, но я подозреваю, что вам лучше разместить их здесь, чем на Amazon, с точки зрения задержки. Очевидно, что здесь вы можете немного потерять скорость, но все же это может быть быстрее, чем встроенный полнотекстовый поиск GAE.

  • Если вам нужен кластер для масштабирования, вы можете использовать ElasticSearch. Имейте в виду, что вам нужно будет правильно настроить многоадресную рассылку на вычислительном движке Google, если вы сделаете это. ElasticSearch предоставляет для этого плагин.

  • Создайте фоновый процесс, который использует очередь push или pull в зависимости от объема ваших данных для обновления поисковых индексов. Частота будет зависеть от того, насколько «свежими» вам нужны ваши данные. Решение о выталкивании или вытягивании будет сильно зависеть от вашего объема, но я бы рекомендовал здесь использовать очередь вытягивания с выделенными серверами, отправляемыми вашему поисковому провайдеру. Вам все равно придется это делать с помощью встроенного полнотекстового поиска.

  • Создайте задание уменьшения карты, которое будет помещать все данные в поисковый индекс. Это полезно как для заполнения начальной очереди, так и для периодического «обновления».

Недостатком вышеизложенного является то, что вы резко увеличите количество вызовов выборки URL, которые вы делаете, и данные могут не всегда быть свежими. Последнее нормально в большинстве ситуаций поиска, первое, вероятно, все же дешевле, чем встроенный полнотекстовый поиск, в зависимости от вашего объема. Если данные редко меняются, вы можете делать такие вещи, как дамп в Google Cloud Storage и импортировать таким образом, а не дешевле.

person therewillbesnacks    schedule 16.03.2014
comment
Спасибо за ваши идеи. К сожалению, я не могу проголосовать за ваш ответ. - person hauru; 16.03.2014
comment
Я провел день за чтением индексов Datastore и анализом Appstats, и теперь у меня более ясная картина. Мне еще предстоит провести более подробный анализ моего случая, но все это не выглядит многообещающе. Хотя ваше предложение звучит немного пугающе для меня. Возможно, было бы проще просто использовать CloudSQL? - person hauru; 16.03.2014
comment
Страшный? Если вам нужен полнотекстовый фасетный поиск, вам нужно его создать. Для этого стандартно отправлять данные из одного хранилища данных в другое. Обычно это подпадает под термин «постоянство полигота». Ваш ответ все равно, что сказать, что я хочу бесплатный обед. Вы должны работать, чтобы получить результат. Более того, как сбрасывание вещей в CloudSQL делает это намного проще? Он может работать или не работать вообще в зависимости от вашей архитектуры. Если бы вы сделали это, вы все еще могли бы двигаться к чему-то вроде Lucene, Solr, Elasticsearch. Либо реализуйте требования, которые у вас есть, либо идите на некоторые компромиссы. - person therewillbesnacks; 16.03.2014
comment
Понятно, спасибо. Не имея ранее опыта работы с крупномасштабными приложениями, GAE/CloudSQL показался мне способом создания среды, одновременно масштабируемой и похожей по удобству на стандартную установку с одним экземпляром * на основе SQL, где действительно такой вид поиска доступен почти всегда. коробки. Но, возможно, на этом уровне все не так просто. - person hauru; 17.03.2014
comment
Все масштабируется, но только до определенной точки по определению. Это будет зависеть от ваших данных, объема, трафика, ресурсов и ряда других факторов. Вы можете использовать полнотекстовое решение MySQL, но оно не будет обслуживать большое количество одновременных пользователей с временем запроса меньше секунды. Каковы ваши точные требования? Учитывая то, что вы говорите, вы, кажется, согласны с моим ответом - не используйте GAE, поищите где-нибудь еще. Я привел вам пример надежного решения для существующего приложения GAE Datastore. Если вы не привязаны к GAE, я предлагаю не использовать его для полнотекстового решения SQL. - person therewillbesnacks; 17.03.2014
comment
Продолжая мой комментарий выше - если вам нужен SQL, я не вижу смысла использовать здесь GAE. Вам лучше разместить его у провайдера, такого как Amazon, с большим контролем. Это только ограничит ваши возможности из-за требований песочницы, или, по крайней мере, вам придется делать то, что я написал выше; использовать Google Compute Engine. Не планируйте масштабируемость, которая, по вашему мнению, вам не понадобится. Точно так же, если вам это нужно, будьте готовы проделать большую работу. Хранилище данных GAE предназначено для приложений с большими наборами данных, которым требуется решение NoSQL. Тот факт, что это Google, не означает, что он будет масштабироваться и работать автоматически. - person therewillbesnacks; 17.03.2014
comment
Нам нужна масштабируемость и надежность, поэтому был выбран GAE/Datastore. Первая итерация проекта в любом случае будет экспериментальной, поэтому, если что-то пойдет не так, мы можем в конечном итоге перенести ее на какую-то другую платформу. На данный момент мы решили отказаться от фасетного поиска и предоставить текстовый поиск в виде отдельной функции (используя Search API). Возможно, мы попробуем подход, изложенный в вашем ответе, т.е. отдельная инфраструктура для поиска. - person hauru; 18.03.2014