Où / Comment adapter Solr dans l'application ASP.net MVC (en utilisant NHibernate / Pattern Repository)

StackOverflow https://stackoverflow.com/questions/3672605

Question

Je suis actuellement au milieu d'une application basée sur des questions assez grande / réponse (un peu comme StackOverflow / answerbag.com) Nous utilisons SQL (Azure) et NHibernate pour l'accès aux données et MVC pour l'application de l'interface utilisateur.

Jusqu'à présent, le schéma est à peu près le long des lignes du stackoverflow db dans le sens que nous avons un seul Publier Table (contient à la fois des questions / réponses)

va probablement utiliser quelque chose le long des lignes de l'interface référentiel suivant:

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);
}

Ma question est: Où / comment pourrais-je adapter solr dans ce pour une meilleure interrogation de ces « messages » (Je vais utiliser solrnet pour la communication réelle avec Solr)

Idéalement, j'utiliser le db SQL comme un simple magasin- persistant La majeure partie des opérations ci-dessus IQueryable se déplacerait dans une sorte de classe SolrFinder (ou quelque chose comme ça)

La propriété du corps est celui qui cause les problèmes actuellement -. Il est assez grand, et ralentit les requêtes sur SQL

Mon problème principal est, par exemple, si quelqu'un « mises à jour » un post - ajoute une nouvelle étiquette, par exemple, alors ce poste entier ont besoin réindexation. De toute évidence, cette opération nécessitera une requête comme ceci:

  

"SELECT * FROM POST WHERE ID = xyz"

Ce sera bien sûr, être très lent. Solrnet a un NHibernate mais je crois Infrastructure d'cela sera le même résultat que ci-dessus?

Je pensais que d'une façon de contourner cela, que je voudrais votre avis sur:

  • Ajout de l'ID à une file d'attente (SQS ou quelque chose amazon - i comme la facilité d'utilisation avec cela)
  • Avoir un service (ou groupe de services) quelque part que faire ce qui précède requête mentionnée, construire le document, et ajoutez-le à solr.

Un autre problème que je vais avoir avec ma conception: Où la méthode « réindexation » (s) être appelées à partir? Le contrôleur MVC? ou devrais-je avoir une classe de type « Postservice », qui enveloppe l'instance de IPostRepository?

Les pointeurs sont grandement reçus sur celui-ci!

Était-ce utile?

La solution

Sur le site e-commerce que je travaille, nous utilisons Solr pour fournir facettage rapide et la recherche du catalogue des produits. (En termes geek non Solr, cela signifie que les "cartes ATI (34), NVIDIA (23), Intel (5)" style de liens de navigation que vous pouvez utiliser pour forer vers le bas par le biais de catalogues de produits sur des sites comme Zappos, Amazon, NewEgg et Lowe.)

Ceci est parce que Solr est conçu pour faire ce genre de choses vite et bien, et d'essayer de faire ce genre de chose efficacement dans une base de données relationnelle traditionnelle est, bien, ne va se passer, sauf si vous voulez commencer à ajouter et enlever indices à la volée et aller EAV complète, qui est juste toux Magento toux stupide. Donc, notre base de données SQL Server est la banque de données « faisant autorité », et les index Solr sont en lecture seule « projections » de ces données.

Vous êtes avec moi jusqu'à présent parce qu'il semble que vous êtes dans une situation similaire. L'étape suivante consiste à déterminer si oui ou non il est OK que les données de l'indice Solr peuvent être légèrement rassis. Vous avez probablement accepté le fait que ce sera un peu fade, mais les prochaines décisions sont

  • Comment rassis est trop fade?
  • Quand est-vitesse de la valeur I ou caractéristiques sur l'interrogation caducité?

Par exemple, j'ai ce que j'appelle le « travailleur », qui est un service Windows qui utilise Quartz.NET pour exécuter les implémentations C # de IJob périodiquement. Toutes les 3 heures, l'un de ces emplois qui est exécuté est le RefreshSolrIndexesJob, et tout ce travail est fait un ping HttpWebRequest vers http://solr.example.com/dataimport?command=full-import. En effet, nous utilisons intégré dans Solr DataImportHandler pour téter réellement dans les données de la base de données SQL; le travail a juste à « toucher » cette URL périodiquement pour faire le travail de synchronisation. Parce que le DataImportHandler engage les changements périodiquement, tout cela est en cours d'exécution en arrière-plan efficace, transparent pour les utilisateurs du site Web.

Cela ne signifie pas que l'information dans le catalogue des produits peut être jusqu'à 3 heures rassis. Un utilisateur peut cliquer sur un lien pour « Medium En stock (3) » sur la page du catalogue (puisque ce genre de données à facettes est généré par l'interrogation SOLR) mais voir sur la page détaillée du produit qui ne médiums sont en stock (depuis sur ce , les informations concernant la quantité est une des rares choses pas mises en cache et Interrogation directement contre la base de données). Ceci est ennuyeux, mais généralement rare dans notre scénario en particulier (nous sommes raisonnablement petites entreprises et non que trafic élevé), et il sera fixé en 3 heures de toute façon quand nous reconstruisons à nouveau tout l'indice de zéro, donc nous avons accepté cela comme un compromis raisonnable.

Si vous ne pouvez accepter ce degré de « caducité », alors ce processus de travail de fond est une bonne façon d'aller. Vous pouvez prendre l'approche « reconstruire la chose quelques heures », ou votre dépôt pourrait insérer l'ID dans une table, par exemple, dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr, puis un processus d'arrière-plan peut périodiquement parcourons cette table et mise à jour uniquement les documents Solr si la reconstruction l'index entier à partir de zéro n'est pas raisonnable compte tenu périodiquement la taille ou la complexité de votre ensemble de données.

Une troisième approche est d'avoir votre spawn dépôt d'un fil d'arrière-plan qui met à jour l'index Solr en ce qui concerne ce document courant plus ou moins en même temps, de sorte que les données ne sont rassis pendant quelques secondes:

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);
    }
}

Mais si cette explosion pour une raison quelconque, vous risquez de manquer des mises à jour à Solr, il est donc toujours une bonne idée d'avoir Solr faire un périodique « souffler tout de suite et rafraîchir », ou un arrière-plan reaper services de type travailleur qui contrôle pour les données hors de ce jour dans tout le monde Solr une fois dans une lune bleue.

En ce qui concerne l'interrogation de ces données à partir Solr, il y a quelques approches que vous pouvez prendre. L'une est de cacher le fait qui existe Solr entièrement par les méthodes de la Républiqueository. Personnellement, je ne recommande pas cela parce que les chances sont votre schéma Solr va être sans vergogne adaptée à l'interface utilisateur qui accédera à ces données; nous avons déjà pris la décision d'utiliser Solr pour fournir facettage facile, le tri et l'affichage rapide des informations, donc nous pourrions aussi bien l'utiliser dans toute son étendue. Cela signifie faire explicite dans le code lorsque nous entendons l'accès Solr et quand nous voulons accéder à la mise à jour, l'objet de base de données non mises en cache.

Dans mon cas, je finis à l'aide de NHibernate pour faire l'accès CRUD (chargement d'un ItemGroup, futzing avec ses règles de prix, puis l'enregistrer en arrière), renoncer au modèle référentiel parce que je ne vois pas généralement sa valeur lorsque NHibernate et ses applications sont déjà rendus analytiques la base de données. (Ceci est un choix personnel.)

Mais lors de l'interrogation sur les données, je sais très bien si je l'utilise à des fins orientées catalogue (je me soucie de Vitesse et interrogation ) ou pour l'affichage dans une table sur une application administrative back-end (je me soucie de monnaie ). Pour l'interrogation sur le site Web, j'ai une interface appelée ICatalogSearchQuery. Il a une méthode Search() qui accepte un SearchRequest où je définir quelques paramètres - facettes sélectionnés, les termes de recherche, numéro de page, le nombre d'articles par page, etc .-- et redonne une SearchResult - facettes restantes, le nombre de résultats, les résultats sur cette page, etc. trucs ennuyeux Jolie.

Là où ça devient intéressant est que la mise en œuvre de cette ICatalogSearchQuery utilise une liste de ICatalogSearchStrategys dessous. La stratégie par défaut, le SolrCatalogSearchStrategy, frappe Solr directement via un HttpWebRequest et l'analyse XML ancienne plaine dans le HttpWebResponse (ce qui est beaucoup plus facile à utiliser, à mon humble avis, que certains des bibliothèques clientes SOLR, mais ils se sont améliorés depuis que je dernière les regardait il y a plus d'un an). Si cette stratégie jette une exception ou vomitifs pour une raison quelconque, le DatabaseCatalogSearchStrategy frappe la base de données SQL directement - même si elle ne tient pas compte des paramètres du SearchRequest, comme facettage ou la recherche de texte avancé, puisque c'est inefficace à faire là-bas et est toute la raison nous utilisons Solr en premier lieu. L'idée est que généralement SOLR est de répondre à mes demandes de recherche rapidement dans la gloire complète, mais si quelque chose explose et SOLR descend, puis les pages du catalogue du site peut encore fonctionner en « mode de fonctionnalité réduite » en appuyant sur la base de données un ensemble limité de fonctionnalités directement. (Étant donné que nous avons fait explicitement dans le code que c'est une recherche, cette stratégie peut prendre quelques libertés en ignorant certains des paramètres de recherche sans se soucier de affecter les clients trop sévèrement.)

plats à emporter Key: Ce qui est important est que la décision d'effectuer une requête sur un éventuellement-rassis magasin de données par rapport à la banque de données faisant autorité a été explicite - si Je veux vite, peut-être des données périmées avec des fonctionnalités de recherche avancées, j'utilise ICatalogSearchQuery. Si je veux lent, des données à jour avec l'insert / mise à jour / capacité de suppression, j'utilise les requêtes nommées NHibernate (ou un dépôt dans votre cas). Et si je fais un changement dans la base de données SQL, je sais que le service des travailleurs hors processus mettra à jour Solr éventuellement, faire des choses par la suite cohérente. (Et si quelque chose était vraiment important, je pourrais diffuser un événement ou un ping sur le magasin SOLR directement, en disant à la mise à jour, peut-être dans un thread d'arrière-plan si je devais.)

L'espoir qui vous donne un aperçu.

Autres conseils

Nous utilisons solr pour interroger une base de données importante de produits. Environ 1 million de produits, et 30 magasins.

Ce que nous avons fait est que nous avons utilisé les déclencheurs sur la table des produits et tables de stock sur notre serveur Sql.

Chaque fois qu'une ligne est changé drapeaux du produit à réindexer. Et nous avons un service Windows qui saisit ces produits et de les envoyer à Solr toutes les 10 secondes. (Avec une limite de 100 produits par lot).

Il est super efficace, l'information en temps quasi-réel pour le stock.

Si vous avez un grand champ de texte (votre champ « corps »), alors oui, réindexer en arrière-plan. Les solutions que vous avez mentionnées (file d'attente ou d'un service d'arrière-plan périodique) feront.

contrôleurs MVC devrait être inconscients de ce processus.

Je remarqué que vous avez IQueryables dans votre interface référentiel. SolrNet ne fait pas à un autre fournisseur de LINQ . Quoi qu'il en soit, si ces opérations sont tout ce que vous allez faire avec Solr (à savoir pas facettage), vous voudrez peut-être envisager d'utiliser à la place Lucene.Net, qui ne à un autre fournisseur de LINQ.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top