Подтвердить что ты не робот

Где/Как установить Solr в приложение ASP.net MVC (с использованием шаблона nHibernate/Repository)

Сейчас я нахожусь в середине достаточно большого вопроса на основе ответа на вопрос (вроде stackoverflow/answerbag.com) Мы используем SQL (Azure) и nHibernate для доступа к данным и MVC для приложения пользовательского интерфейса.

До сих пор схема примерно соответствовала строкам stackoverflow db в том смысле, что у нас есть одна таблица Post (содержит вопросы и ответы)

Вероятно, что-то будет использовать по строкам следующего интерфейса репозитория:

public interface IPostRepository
{
    void PutPost(Post post);
    void PutPosts(IEnumerable<Post> posts);

    void ChangePostStatus(string postID, PostStatus status);

    void DeleteArtefact(string postId, string artefactKey);
    void AddArtefact(string postId, string artefactKey);

    void AddTag(string postId, string tagValue);
    void RemoveTag(string postId, string tagValue);

    void MarkPostAsAccepted(string id);
    void UnmarkPostAsAccepted(string id);

    IQueryable<Post> FindAll();
    IQueryable<Post> FindPostsByStatus(PostStatus postStatus);
    IQueryable<Post> FindPostsByPostType(PostType postType);
    IQueryable<Post> FindPostsByStatusAndPostType(PostStatus postStatus, PostType postType);
    IQueryable<Post> FindPostsByNumberOfReplies(int numberOfReplies);
    IQueryable<Post> FindPostsByTag(string tag);
}

Мой вопрос: Где/как бы я вписывал solr в это для лучшего запроса этих "Сообщений", (Я буду использовать solrnet для фактической связи с Solr)

В идеале я бы использовал SQL DB как просто постоянный магазин, Основная часть вышеперечисленных операций IQueryable переместилась бы в какой-то класс SolrFinder (или что-то в этом роде)

Свойство Body является тем, которое вызывает проблемы в настоящее время - оно довольно велико и замедляет запросы на sql.

Моя основная проблема заключается, например, в том, что если кто-то "обновляет" сообщение - добавляет новый тег, например, то всему сообщению потребуется повторная индексация. Очевидно, для этого потребуется такой запрос:

"SELECT * FROM POST WHERE ID = xyz"

Это, конечно, будет очень медленным. Solrnet имеет объект nHibernate, но я верю, что это будет тот же результат, что и выше?

Я подумал об этом, о чем я хотел бы взглянуть на:

  • Добавление идентификатора в очередь (amazon sqs или что-то - мне нравится простота использования с этим)
  • Если у вас есть сервис (или куча сервисов), который выполняет вышеупомянутый запрос, создайте документ и снова добавьте его в solr.

Еще одна проблема, с которой я сталкиваюсь: Откуда должен быть вызван метод переиндексации? Контроллер MVC? или должен ли я иметь класс типа "PostService", который обертывает экземпляр IPostRepository?

Любые указатели получаются на этом!

4b9b3361

Ответ 1

На сайте электронной коммерции, над которым я работаю, мы используем Solr для быстрой аранжировки и поиска каталога продуктов. (В терминах, отличных от Solr, это означает, что стиль навигационных ссылок "ATI Cards (34), NVIDIA (23), Intel (5)" можно развернуть по каталогам продуктов на таких сайтах, как Zappos, Amazon, NewEgg и Lowe's.)

Это потому, что Solr предназначен для того, чтобы делать это быстро и хорошо, и попытка эффективно делать это в традиционной реляционной базе данных, ну, не произойдет, если вы не захотите начать добавлять и удалять индексы "на лету" и идут полным EAV, а это просто кашель Magento кашель глупый. Таким образом, наша база данных SQL Server является "авторитетным" хранилищем данных, а индексы Solr являются "проекциями" только для чтения этих данных.

Ты со мной до сих пор, потому что похоже, что ты в подобной ситуации. Следующим шагом является определение того, хорошо или нет, что данные в индексе Solr могут быть немного устаревшими. Вероятно, вы приняли тот факт, что он будет несколько устаревшим, но следующие решения:

  • Насколько устаревший слишком устарел?
  • Когда я могу оценивать скорость или запрашивать функции по сравнению с неподвижностью?

Например, у меня есть то, что я называю "Рабочим", который является службой Windows, которая использует Quartz.NET для выполнения С# IJob реализации. Каждые 3 часа одно из этих заданий, которое выполняется, - это RefreshSolrIndexesJob, и все, что делает это, - ping a HttpWebRequest до http://solr.example.com/dataimport?command=full-import. Это связано с тем, что мы использовали Solr встроенный DataImportHandler, чтобы фактически всасывать данные из базы данных SQL; работа просто должна "касаться" этого URL-адреса, чтобы синхронизировать работу. Поскольку DataImportHandler периодически фиксирует изменения, все это эффективно работает в фоновом режиме, прозрачно для пользователей веб-сайта.

Это означает, что информация в каталоге продуктов может задерживаться до 3 часов. Пользователь может щелкнуть ссылку на "Средний на складе (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, futzing с его правилами ценообразования, а затем сохранение его обратно), переходя из шаблона репозитория, потому что я обычно не вижу его значения когда NHibernate и его сопоставления уже абстрагируют базу данных. (Это личный выбор.)

Но когда вы запрашиваете данные, я очень хорошо знаю, использую ли я его для целей, ориентированных на каталоги (я забочусь о скорости и запросах), или для отображения в таблице на внешнем административном приложении (я забочусь о валюта). Для запросов на веб-сайте у меня есть интерфейс под названием ICatalogSearchQuery. Он имеет метод Search(), который принимает SearchRequest, где я определяю некоторые параметры - выбранные грани, поисковые термины, номер страницы, количество элементов на странице и т.д. - и возвращает SearchResult - оставшиеся грани, количество результатов, результаты на этой странице и т.д. Довольно скучные вещи.

Интересно, что реализация этого ICatalogSearchQuery использует список ICatalogSearchStrategy под ним. Стратегия по умолчанию, SolrCatalogSearchStrategy, попадает в SOLR напрямую через простой старомодный HttpWebRequest и анализирует XML в HttpWebResponse (который намного проще использовать, IMHO, чем некоторые из клиентских библиотек SOLR, хотя они возможно, улучшились с тех пор, как я последний раз смотрел на них больше года назад). Если по какой-либо причине эта стратегия выдает исключение или рвоту, то DatabaseCatalogSearchStrategy напрямую попадает в базу данных SQL, хотя игнорирует некоторые параметры SearchRequest, такие как огранка или расширенный поиск текста, поскольку это неэффективно для этого и это вся причина, по которой мы используем Solr. Идея состоит в том, что обычно SOLR быстро отвечает на запросы поиска в полнофункциональной славе, но если что-то взрывается и SOLR падает, тогда страницы каталога сайта могут по-прежнему функционировать в режиме ограниченной функциональности, нажимая базу данных с помощью ограниченный набор функций. (Поскольку мы сделали явным в коде, что это поиск, эта стратегия может принимать некоторые ограничения при игнорировании некоторых параметров поиска, не беспокоясь о том, что они слишком сильно влияют на клиентов.)

Key takeaway: Важно то, что решение о выполнении запроса относительно возможно устаревшего хранилища данных по сравнению с авторитетным хранилищем данных было сделано явным - если мне нужны быстрые, возможно устаревшие данные с расширенными функциями поиска, я использую ICatalogSearchQuery. Если мне нужны медленные, обновленные данные с возможностью вставки/обновления/удаления, я использую NHibernate с именем query (или репозиторий в вашем случае). И если я вношу изменения в базу данных SQL, я знаю, что служба рабочего процесса вне процесса будет в конечном итоге обновлять Solr, что в конечном итоге будет согласовано. (И если что-то действительно важно, я мог бы транслировать событие или напрямую пинговать хранилище SOLR, сообщая ему обновить, возможно, в фоновом потоке, если бы мне пришлось.)

Надеюсь, это даст вам некоторое представление.

Ответ 2

Мы используем solr для запроса большой базы данных продукта. Около 1 миллиона продуктов и 30 магазинов.

Что мы сделали, мы использовали триггеры в таблице продуктов и столах на нашем сервере Sql.

Каждый раз, когда строка изменяется, флажок переопределяется. И у нас есть служба Windows, которая захватывает эти продукты и отправляет их в Solr каждые 10 секунд. (С пределностью до 100 продуктов за партию).

Это суперэффективная, почти реальная информация о запасе.

Ответ 3

Если у вас есть большое текстовое поле (поле "тело" ), то да, переиндексировать в фоновом режиме. Решения, которые вы упомянули (очередь или периодическое фоновое обслуживание), будут выполнены.

Контроллеры MVC не должны забывать об этом процессе.

Я заметил, что у вас есть IQueryables в вашем интерфейсе репозитория. SolrNet в настоящее время имеет поставщик LINQ. В любом случае, если эти операции - это все, что вы собираетесь делать с Solr (т.е. Без огранки), вы можете захотеть вместо этого использовать Lucene.Net, у которого есть поставщик LINQ.