solrをASP.NET MVCアプリに適合させる方法(nhibernate /リポジトリパターンを使用)
-
01-10-2019 - |
質問
私は現在、SQL(Azure)とNhibernateを使用して、UIアプリにMVCを使用しているSQL(Azure)とNhibernateを使用している、かなり大きな質問 /回答ベースのアプリケーション(Stackoverflow / Answerbag.comのような種類)の真っin中にいます。
これまでのところ、スキーマは、単一を持っているという意味で、StackoverFlow DBのラインに沿っています 役職 テーブル(両方の質問 /回答が含まれています)
おそらく、次のリポジトリインターフェイスの行に沿って何かを使用する予定です。
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クラス(またはそのようなもの)に移動します。
身体の特性は、現在問題を引き起こすものです - それはかなり大きく、SQLのクエリを遅くしています。
私の主な問題は、たとえば、誰かが投稿を「更新」する場合、たとえば新しいタグを追加する場合、その投稿全体が再インデックスする必要があることです。明らかに、これを行うには、次のようなクエリが必要です。
「select * from post where id = xyz」
もちろん、これは非常に遅くなります。 SolrnetにはNhibernateの施設がありますが、これは上記と同じ結果になると思いますか?
私はこれを回避する方法を考えました。
- キューにIDを追加します(Amazon SQSか何か - これで使いやすいです)
- 上記のクエリを行う場所にサービス(または多数のサービス)を持ち、ドキュメントを構築し、それをsolrに再添加します。
私が私のデザインで抱えている別の問題:「再インデックス」メソッドはどこから呼び出されるべきですか? MVCコントローラー?または、iPosTrepositoryのインスタンスをラップする「Postservice」タイプのクラスが必要ですか?
ポインターはこれで大いに受け取られます!
解決
私が働いているeコマースサイトでは、SolRを使用して、製品カタログの高速なファセットと検索を提供しています。 (非SOLRオタクの用語では、これは「ATIカード(34)、Nvidia(23)、Intel(5)のスタイルを意味します。 Newegg、Lowe's。)
これは、solrがこの種のことを迅速かつ順調に行うように設計されており、従来のリレーショナルデータベースでこの種のことを効率的に行こうとすることは、まあ、起こりそうにないためです。フライアンドフルEAV、それはまさにです 咳 マゼント 咳 バカ。したがって、当社のSQL Serverデータベースは「権威ある」データストアであり、SOLRインデックスはそのデータの読み取り専用の「投影」です。
あなたは同じような状況にあるように聞こえるので、あなたはこれまで私と一緒にいます。次のステップは、SOLRインデックスのデータがわずかに古くなっている可能性があることが問題であるかどうかを判断することです。あなたはおそらくそれがやや古くなるという事実を受け入れたでしょうが、次の決定は
- どれほど古すぎるのは古すぎますか?
- 速度よりも速度またはクエリ機能のクエリをいつ評価できますか?
たとえば、私は「ワーカー」と呼んでいるものを持っています。 Quartz.net C#を実行するには IJob
定期的に実装。 3時間ごとに、実行されるこれらのジョブの1つは RefreshSolrIndexesJob
, 、そしてその仕事はすべてをpingします HttpWebRequest
に http://solr.example.com/dataimport?command=full-import
. 。これは、solrの組み込みを使用しているためです DataImporthandler 実際にSQLデータベースからデータを吸い込む。ジョブは、同期を機能させるために、そのURLを定期的に「タッチ」する必要があります。 DataImporthandlerは定期的に変更をコミットしているため、これはすべてバックグラウンドで効果的に実行され、Webサイトのユーザーに透明になっています。
これは、製品カタログの情報が最大3時間の古いものになる可能性があることを意味します。ユーザーは、カタログページの「Medium in Stock(3)」のリンクをクリックする可能性があります(この種のファセットデータはSOLRをクエリすることで生成されるため)が、製品の詳細ページには在庫がないことを確認してください(これはこれでページ、数量情報は数少ないものの1つです いいえ キャッシュされ、データベースに対して直接照会されました)。これは迷惑ですが、一般的に特にシナリオではまれです(私たちはかなり中小企業であり、そうではありません それ 交通量が多い)、そしてそれはとにかくインデックス全体をゼロから再構築するときに3時間で修正されるので、これを合理的なトレードオフとして受け入れました。
この程度の「頑固さ」を受け入れることができれば、このバックグラウンドワーカープロセスは良い方法です。 「数時間ごとにすべてを再構築する」アプローチを取ることができます。または、リポジトリがIDをテーブルに挿入して、たとえば、 dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr
, 、その後、バックグラウンドプロセスは、データセットのサイズまたは複雑さを考えると、定期的にインデックス全体をゼロから再構築することが妥当ではない場合、そのテーブルを定期的にスキャンしてSOLRのドキュメントのみを更新できます。
3番目のアプローチは、リポジトリにその現在のドキュメントに関する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に定期的な「すべてを吹き飛ばして更新」するか、OutをチェックするReaper Background Workerタイプのサービスを持たせることをお勧めします。ブルームーンで一度誰もがsolrの日付データ。
SOLRからこのデータを照会するには、いくつかのアプローチがあります。 1つは、solrがリポジトリの方法を介して完全に存在するという事実を隠すことです。私は個人的にこれをお勧めしません。なぜなら、あなたのsolrスキーマはそのデータにアクセスするUIに恥知らずに調整される可能性があるからです。 SolRを使用して、簡単なファセット、並べ替え、情報の迅速な表示を提供することを決定しているため、最大限に使用することもできます。これは、SOLRにアクセスすることを意味し、最新のキャッシュされていないデータベースオブジェクトにアクセスすることを意味する場合、コードで明示的にすることを意味します。
私の場合、私はnhibernateを使用してCrudアクセスを実行することになります( ItemGroup
, 、価格設定ルールを使用してフッツをかけてから保存します)、リポジトリパターンを禁じています。これは、nhibernateとそのマッピングがすでにデータベースを抽象化している場合、その価値が通常表示されないためです。 (これは個人的な選択です。)
しかし、データをクエリするとき、カタログ指向の目的でそれを使用している場合、私はかなりよく知っています(私は気にします 速度 と クエリ)またはバックエンド管理アプリケーションのテーブルに表示するため(私は気にします 通貨)。 Webサイトでクエリするために、私は呼ばれるインターフェイスを持っています ICatalogSearchQuery
. 。それはあります Search()
aを受け入れる方法 SearchRequest
選択されたファセット、検索用語、ページ番号、ページごとのアイテム数などを定義し、 SearchResult
- 修正ファセット、結果の数、このページの結果など。かなり退屈なもの。
興味深いところは、その実装が ICatalogSearchQuery
のリストを使用しています ICatalogSearchStrategy
s下。デフォルトの戦略、 SolrCatalogSearchStrategy
, 、昔ながらの単純な介して、solrを直接ヒットします HttpWebRequest
XMLを解析します HttpWebResponse
(Imho、Solrクライアントライブラリの一部よりもはるかに使いやすいですが、1年以上前に最後に見たので、より良くなったかもしれません)。その戦略が何らかの理由で例外または嘔吐を投げた場合、 DatabaseCatalogSearchStrategy
SQLデータベースに直接ヒットしますが、 SearchRequest
, 、ファセットや高度なテキスト検索のように、それはそこでは非効率的であり、そもそもSolRを使用している理由が全体であるためです。アイデアは、通常、Solrがフル機能の栄光で私の検索要求に迅速に答えているが、何かが爆発してSolrがダウンした場合、サイトのカタログページはデータベースをwithに押して「縮小機能モード」で機能することができるということです。限られた機能セットは直接セットされています。 (これが検索であることをコードで明示したので、その戦略は、クライアントにあまりにもひどく影響を与えることを心配することなく、いくつかの検索パラメーターを無視することにいくつかの自由をとることができます。)
重要なテイクアウト: 重要なのは、ゼロのデータストアと権威あるデータストアに対してクエリを実行する決定が行われたことです 明示的- 高度な検索機能を備えた高速で、おそらく古いデータが必要な場合、私は使用します ICatalogSearchQuery
. 。挿入/更新/削除機能を備えた遅い最新のデータが必要な場合は、Nhibernateの名前のクエリ(またはあなたの場合のリポジトリ)を使用します。また、SQLデータベースに変更を加えると、プロセス不在の労働者サービスが最終的にSOLRを更新し、最終的には一貫性があることを知っています。 (そして、何かが本当に重要だった場合、イベントをブロードキャストしたり、Solrストアを直接Pingしたりすることができます。
それがあなたにいくつかの洞察を与えることを願っています。
他のヒント
SOLRを使用して、大規模な製品データベースを照会します。約100万の製品、30の店舗。
私たちがしたことは、製品テーブルとSQLサーバーのストックテーブルでトリガーを使用したことです。
行が変更されるたびに、製品にフラグが付けられます。また、これらの製品をつかみ、10秒ごとにSolRに投稿するWindowsサービスがあります。 (バッチごとに100製品の制限があります)。
それは非常に効率的で、在庫のほぼリアルタイム情報です。
大きなテキストフィールド(「ボディ」フィールド)がある場合は、はい、バックグラウンドで再インドを再インドします。言及したソリューション(キューまたは定期的な背景サービス)が行います。
MVCコントローラーは、このプロセスを忘れてはなりません。
リポジトリインターフェイスにiQueryablesがあることに気付きました。 Solrnetは現在ありません LINQプロバイダーを持っています. 。とにかく、これらの操作がSolrで行うすべての場合(つまり、ファセットはありません)、代わりにlucene.netを使用することを検討することをお勧めします。 します LINQプロバイダーを持っています。