На сайте электронной коммерции, на котором я работаю, мы используем Solr для быстрого поиска и поиска в каталоге товаров.(В терминах, не связанных с Solr, это означает навигационные ссылки в стиле «ATI Cards (34), NVIDIA (23), Intel (5)»), которые можно использовать для перехода по каталогам продуктов на таких сайтах, как Zappos, Amazon,NewEgg и Lowe's.)
Это потому, что Solr разработан, чтобы делать такие вещи быстро и хорошо, и попытки делать такие вещи эффективно в традиционной реляционной базе данных, ну, в общем, не произойдет, если только вы не хотите начинать добавлять и удалять индексы на лету и переходить на полную EAV, что просто кашель Magento кашель глупо.Таким образом, наша база данных SQL Server является «авторитетным» хранилищем данных, а индексы Solr являются «проекциями» этих данных только для чтения.
Пока вы со мной, потому что, похоже, вы находитесь в похожей ситуации.ситуация.Следующим шагом является определение того, нормально ли это, что данные в индексе Solr могут быть немного устаревшими.Вы, вероятно, согласились с тем фактом, что это будет несколько устаревшим, но следующие решения:
- Как устаревшие слишком устарели?
- Когда я оцениваю скорость или запрашиваю функции по устареванию?
Например, у меня есть то, что я называю «Рабочий», - это служба Windows, которая использует Quartz.NET для периодического выполнения реализаций C # IJob
.Каждые 3 часа одно из выполняемых заданий - это RefreshSolrIndexesJob
, и все, что выполняет это задание, - пинг HttpWebRequest
до http://solr.example.com/dataimport?command=full-import
.Это потому, что мы используем встроенный в Solr DataImportHandler для фактического всасывания данных из базы данных SQL;задание просто периодически «трогает» этот URL, чтобы обеспечить синхронизацию.Поскольку DataImportHandler периодически фиксирует изменения, все это эффективно работает в фоновом режиме, прозрачно для пользователей веб-сайта.
Это означает, что информация в каталоге продуктов может устареть до 3 часов.Пользователь может щелкнуть ссылку «Medium In Stock (3)» на странице каталога (так как этот вид граненых данных генерируется путем запроса SOLR), но затем увидеть на странице сведений о продукте, что на складе нет носителей (так как на этомстраница, информация о количестве - это одна из немногих вещей, которые не кэшируются и запрашиваются непосредственно в базе данных).Это раздражает, но, как правило, редко встречается в нашем конкретном сценарии (мы - достаточно малый бизнес, а не с большим трафиком), и в любом случае это будет исправлено через 3 часа, когда мы снова перестроим весь индекс с нуляТаким образом, мы приняли это как разумный компромисс.
Если вы можете принять эту степень «устаревания», то этот фоновый рабочий процесс - хороший путь.Вы можете использовать подход «перестраивать все каждые несколько часов», или ваш репозиторий может вставить идентификатор в таблицу, скажем, dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr
, и тогда фоновый процесс может периодически сканировать эту таблицу и обновлять только те документы в Solr.если периодически восстанавливать весь индекс с нуля нецелесообразно, учитывая размер или сложность вашего набора данных.
Третий подход заключается в том, чтобы ваш репозиторий порождал фоновый поток, который обновляет индекс Solr по отношению к этому текущему документу.более или менее в одно и то же время, поэтому данные устаревают только на несколько секунд:
class MyRepository
{
void Save(Post post)
{
// the following method runs on the current thread
SaveThePostInTheSqlDatabaseSynchronously(post);
// the following method spawns a new thread, task,
// queueuserworkitem, whatevever floats our boat this week,
// and so returns immediately
UpdateTheDocumentInTheSolrIndexAsynchronously(post);
}
}
Но если по какой-то причине это взорвется, вы можете пропустить обновления в Solr, так что все равно хорошая идеяпусть Solr будет периодически «выдыхать все и обновлять», или иметь жнецовую справочную службу рабочего типа, которая проверяет устаревшие данные в Solr, каждый раз в синей луне.
Что касается запроса этих данных у Solr, есть несколько подходов, которые вы можете использовать. Один из них заключается в том, чтобы скрыть тот факт, что Solr существует полностью через методы репозитория. Я лично не рекомендую это, потому что есть вероятность, что ваша схема Solr будет бесстыдно адаптирована к пользовательскому интерфейсу, который будет обращаться к этим данным; мы уже приняли решение использовать Solr для обеспечения легкой огранки, сортировки и быстрого отображения информации, поэтому мы могли бы использовать ее в полной мере. Это означает сделать это явным образом в коде, когда мы хотим получить доступ к Solr, и когда мы хотим получить доступ к актуальному некэшируемому объекту базы данных.
В моем случае я в конечном итоге использую NHibernate для доступа к CRUD (загрузка ItemGroup
, просмотр его правил ценообразования, а затем сохранение его обратно), отказываясь от шаблона репозитория, поскольку я обычно не вижу его значения когда NHibernate и его отображения уже абстрагируют базу данных. (Это личный выбор.)
Но при запросе данных я хорошо знаю, использую ли я их для целей каталога (меня интересуют скорость и запросы ) или для отображения в таблица на административном административном приложении (меня волнует валюта ). Для запросов на веб-сайте у меня есть интерфейс под названием ICatalogSearchQuery
. Он имеет метод Search()
, который принимает SearchRequest
, где я определяю некоторые параметры - выбранные фасеты, условия поиска, номер страницы, количество элементов на странице и т. Д. - и возвращает SearchResult
- оставшиеся фасеты , количество результатов, результаты на этой странице и т. д. Довольно скучные вещи.
Интересно, что реализация этого ICatalogSearchQuery
использует список ICatalogSearchStrategy
внизу. Стратегия по умолчанию, SolrCatalogSearchStrategy
, напрямую обращается к SOLR через простой старомодный HttpWebRequest
и анализирует XML в HttpWebResponse
(который намного проще в использовании, IMHO, чем некоторые клиентские библиотеки SOLR, хотя они возможно, стало лучше, так как я последний раз смотрел на них более года назад). Если эта стратегия по какой-то причине вызывает исключение или вызывает рвоту, то DatabaseCatalogSearchStrategy
напрямую попадает в базу данных SQL - хотя она игнорирует некоторые параметры SearchRequest
, такие как фасетирование или расширенный текстовый поиск, поскольку это неэффективно, и это единственная причина, по которой мы используем Solr. Идея состоит в том, что обычно SOLR отвечает на мои поисковые запросы быстро и полнофункционально, но если что-то взорвется и SOLR выйдет из строя, то страницы каталога сайта все еще могут функционировать в «режиме ограниченной функциональности», попав в базу данных с помощью ограниченный набор функций напрямую. (Поскольку в коде мы четко указали, что это поиск, эта стратегия может позволить себе игнорировать некоторые параметры поиска, не беспокоясь о слишком серьезном влиянии на клиентов.)
Вывод ключа: Важно то, что было принято решение выполнить запрос к возможно устаревшему хранилищу данных относительно авторитетного хранилища данных явно - если я хочу быстрые, возможно устаревшие данные с расширенными функциями поиска, я использую ICatalogSearchQuery
. Если я хочу медленные, свежие данные с возможностью вставки / обновления / удаления, я использую именованные запросы NHibernate (или хранилище в вашем случае). И если я внесу изменения в базу данных SQL, я знаю, что внешняя служба Worker в конечном итоге обновит Solr, в результате чего все станет согласованно. (И если что-то действительно важно, я мог бы транслировать событие или напрямую пинговать хранилище SOLR, предлагая обновить его, возможно, в фоновом потоке, если потребуется).
Надеюсь, что это даст вам некоторое представление.