Frage

Ich bin zur Zeit in der Mitte einer ziemlich große Frage / Antwort-basierten Anwendung (Art wie Stackoverflow / answerbag.com) Wir verwenden SQL (Azure) und nHibernate für den Datenzugriff und MVC für den UI-App.

Bisher ist das Schema in etwa entlang der Linien der Stackoverflow db in dem Sinne, dass wir eine einzige Post Tabelle (enthält beide Fragen / Antworten)

Wahrscheinlich etwas nicht benutzen wollen entlang der Linien der folgenden Repository-Schnittstelle:

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

Meine Frage ist: Wo / wie würde ich solr in diese für eine bessere Abfrage dieser „Beiträge“ fit (Ich werde solrnet für die eigentliche Kommunikation mit Solr verwenden)

Idealerweise würde ich die SQL db verwenden als nur eine persistente Store- Der Großteil der oben IQueryable Operationen würden in eine Art SolrFinder Klasse bewegen (oder so ähnlich)

Die Body-Eigenschaft ist derjenige, der die Probleme verursacht derzeit -. Es ist ziemlich groß, und verlangsamen Abfragen auf SQL

Mein Hauptproblem ist, zum Beispiel, wenn jemand „Updates“ ein Post - einen neuen Tag fügt hinzu, zum Beispiel, dann ist die ganze Post Re-Indizierung benötigen. Offensichtlich ist dies tun wird eine Abfrage wie diese benötigt:

"SELECT * FROM POST WHERE ID = xyz"

Dies wird natürlich sehr langsam sein. Solrnet hat eine nHibernate Facility-, aber ich glaube, dass dies das gleiche Ergebnis wie oben sein?

Ich dachte an eine Art und Weise, um dies, das ich Ihre Ansichten möchte auf:

  • Hinzufügen der ID in eine Warteschlange (Amazon SQS oder etwas - ich mag die einfache Bedienung mit dieser)
  • Mit einem Dienst (oder Bündel von Dienstleistungen) irgendwo dass die oben genannten Abfrage tun, konstruieren, um das Dokument und erneut fügen Sie solr.

Ein weiteres Problem, das ich mit meinem Entwurf habe: Wo sollen die „Neuindexierung“ Methode (n) aus aufgerufen werden? Die MVC-Controller? oder sollte ich eine „Postservice“ Typklasse, die die Instanz von IPostRepository hüllt?

Alle Hinweise werden auf diesem ein stark erhalten!

War es hilfreich?

Lösung

Auf der E-Commerce-Website, dass ich arbeiten, verwenden wir Solr schnell zur Verfügung zu stellen Facettierung und die Suche des Produktkatalogs. (In nicht-Solr Aussenseiter bedeutet dies die "ATI-Karten (34), NVIDIA (23), Intel (5)" Stil der Navigations-Links, die Sie verwenden können durch Produktkataloge auf Websites wie Zappos zu Drilldown, Amazon, NewEgg und Lowe).

Das ist, weil Solr gestaltet ist diese Art der Sache zu tun, schnell und gut, und diese Art der Sache in einer traditionellen relationalen Datenbank effizient zu tun versucht, ist, na ja, nicht passieren, es sei denn, Sie starten mögen, das Hinzufügen und Entfernen Indizes on the fly und gehen voll EAV, die nur Husten Magento Husten ist dumm. So ist unsere SQL Server-Datenbank ist der „autoritative“ Datenspeicher und der Solr-Indizes sind schreibgeschützt „Projektionen“ der Daten.

Du bist bei mir so weit, weil es klingt wie Sie in einer ähnlichen Situation sind. Der nächste Schritt ist die Bestimmung, ob es in Ordnung ist, dass die Daten in dem Solr-Index leicht abgestanden sein können. Sie haben wahrscheinlich die Tatsache akzeptiert, dass es etwas abgestanden sein wird, aber die nächsten Entscheidungen

  • Wie veraltet ist zu alt?
  • Wenn ich Wert Geschwindigkeit oder Abfrage von Funktionen über staleness?

Zum Beispiel habe ich, was ich die „Arbeiter“ nennen, die ein Windows-Dienst ist, dass Anwendungen Quartz.NET C # IJob Implementierungen regelmäßig auszuführen. Alle 3 Stunden, einen dieser Jobs, die ausgeführt wird ist die RefreshSolrIndexesJob, und alles, was Arbeit erledigt ist ping ein HttpWebRequest über http://solr.example.com/dataimport?command=full-import. Dies liegt daran, wir verwenden Solr eingebaute in DataImportHandler , um tatsächlich in den Daten aus der SQL-Datenbank saugen; der Job muss nur „berühren“, dass URL in regelmäßigen Abständen die Sync-Arbeit zu machen. Da die DataImportHandler die Änderungen in regelmäßigen Abständen verpflichtet, das ist alles effektiv im Hintergrund läuft, transparent für die Benutzer der Website.

Das bedeutet, dass die Informationen im Produktkatalog sein kann zu 3 Stunden abgestanden. Ein Benutzer kann einen Link für „Medium Auf Lager (3)“ auf der Katalogseite klicken (da diese Art von facettierten Daten durch Abfragen SOLR erzeugt wird), aber dann auf der Produktdetailseite zu sehen, dass keine Medien auf Lagern sind (da auf diesem Seite, die Menge Informationen ist eines der wenigen Dinge, nicht gecached und abgefragten direkt gegen die Datenbank). Das ist ärgerlich, aber in der Regel selten in unserem besonders Szenario (wir ein recht kleines Unternehmen sind und nicht , die High-Traffic), und es wird auf jeden Fall in 3 Stunden festgelegt werden, wenn wir den gesamten Index wieder aufzubauen wieder aus Kratzer, so dass wir dies als ein vernünftiger Kompromiss akzeptiert haben.

Wenn Sie diesen Grad an „staleness“ annehmen können, dann ist dieser Hintergrund-Arbeitsprozess ist ein guter Weg zu gehen. Sie könnten die „wieder aufzubauen, das Ganze alle paar Stunden“ nehmen Ansatz, oder Ihr Repository könnte die ID in eine Tabelle einfügen, sagen wir, dbo.IdentitiesOfStuffThatNeedsUpdatingInSolr, und dann kann ein Hintergrundprozess in regelmäßigen Abständen Scan durch, dass Tabelle und aktualisieren nur die Dokumente in Solr wenn Wiederaufbau regelmäßig der gesamte Index von Grund auf neu ist die Größe oder Komplexität Ihrer Datensatzes gegeben nicht zumutbar.

Ein dritte Ansatz ist Ihr Repository Laich einen Hintergrund-Thread, dass Updates der Solr-Index in Bezug auf dieses aktuelle Dokument zu haben, mehr oder weniger zur gleichen Zeit, so dass die Daten für ein paar Sekunden nur abgestanden sind:

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

Aber wenn diese explodiert aus irgendeinem Grund, können Sie Updates in Solr verpassen, so ist es immer noch eine gute Idee haben Solr eine periodische tun „es Schlag alles weg und aktualisieren“, oder einen Dienst Reaper Hintergrund Worker-Typ haben, dass die Kontrollen für out-of-date Daten in Solr jedem einmal in einem blauen Mond.

Wie für diese Daten von Solr abfragt, es gibt ein paar Ansätze könnten Sie nehmen. Eine davon ist die Tatsache zu verbergen, dass Solr vollständig über die Methoden des Rep existiertository. Ich persönlich nicht dieses empfehlen, weil die Chancen Ihrer Solr Schema sind wird schamlos auf die UI angepasst werden, dass diese Daten zugreifen werden; wir haben bereits die Entscheidung zu verwenden Solr bieten einfache Facettierung, Sortieren und schnelle Anzeige von Informationen gemacht, so dass wir auch sie in vollem Umfang nutzen können. Dieses Mittel macht es im Code explizit, wenn wir den Zugriff auf Solr bedeuten und wenn wir das up-to-date Zugriff bedeuten zu, nicht zwischengespeicherten Datenbankobjekts.

In meinem Fall hat ich am Ende NHibernate up mit dem CRUD Zugang zu tun (ein ItemGroup Laden futzing mit seinen Preisregeln, und dann wieder speichern), das Repository-Muster zu verzichten, weil ich in der Regel nicht seinen Wert sehen, wenn NHibernate und ihre Zuordnungen werden abstrahiert bereits die Datenbank. (Dies ist eine persönliche Entscheidung.)

Aber wenn auf den Daten abfragt, ich weiß recht gut, wenn ich es bin mit für Kataloge-orientierte Zwecke (Ich kümmere mich um Geschwindigkeit und Abfragen ) oder zur Anzeige in einer Tabelle auf einer back-End-Verwaltungsanwendung (ich kümmere mich um Währung ). Für die Abfrage auf der Website, habe ich eine Schnittstelle namens ICatalogSearchQuery. Es hat eine Search() Methode, die eine SearchRequest akzeptiert, wo ich einige Parameter definieren - ausgewählte Facetten, Suchbegriffe, Seitenzahl, Anzahl der Artikel pro Seite, etc .-- und gibt wieder eine SearchResult - verbleibenden Facetten, die Anzahl der Ergebnisse, die Ergebnisse auf dieser Seite, usw. Ziemlich langweilig Zeug.

Wenn es interessant ist, dass die Umsetzung dieser ICatalogSearchQuery unter einer Liste von ICatalogSearchStrategys verwendet. Die Standardstrategie, die SolrCatalogSearchStrategy, SOLR Treffer direkt über einen einfachen altmodischen HttpWebRequest und Parsen der XML in der HttpWebResponse (die viel einfacher zu bedienen ist, IMHO, als einige der SOLR-Client-Bibliotheken, obwohl sie, da ich besser bekommen haben kann zuletzt bei ihnen mehr als ein Jahr sah vor). Wenn diese Strategie eine Ausnahme oder erbricht aus irgendeinem Grund wirft, dann trifft die DatabaseCatalogSearchStrategy die SQL-Datenbank direkt - obwohl es einige Parameter des SearchRequest, wie Facettierung oder erweiterte Textsuche ignoriert, da diese ineffizient ist dort zu tun und ist der ganze Grund wir verwenden Solr in erster Linie. Die Idee ist, dass in der Regel SOLR ist meine Suchanfrage schnell in voll funktions Herrlichkeit zu beantworten, aber wenn etwas explodiert und SOLR geht, dann wird die Katalogseiten der Website kann noch Funktion in „reduzierten Funktionsmodus“ durch die Datenbank schlägt mit eine eingeschränkte Funktion direkt eingestellt. (Da wir im Code explizit gemacht haben, dass dies eine Suche, die Strategie einige Freiheiten einige der Suchparameter zu ignorieren, ohne sich Gedanken über die Kunden zu stark zu beeinflussen. Dauern kann)

Key Mitnehmen: Wichtig ist, dass die Entscheidung, eine Abfrage eines möglicherweise veralteten Datenspeicher auszuführen gegen die maßgebliche Datenspeicher gemacht worden ist explizite - wenn ich möchte schnell, möglicherweise veraltete Daten mit erweiterten Suchfunktionen, ich ICatalogSearchQuery verwenden. Wenn ich langsam will, up-to-date Daten mit dem insert / update / delete Fähigkeit, verwende ich NHibernate benannten Abfragen (oder ein Repository in Ihrem Fall). Und wenn ich eine Änderung in der SQL-Datenbank mache, weiß ich, dass der Out-of-Process-Worker-Service Solr schließlich aktualisieren, die Dinge schließlich konsistent. (Und wenn etwas wirklich wichtig war, konnte ich ein Ereignis übertragen oder SOLR Speicher direkt ping, es zu aktualisieren sagen, möglicherweise in einem Hintergrund-Thread, wenn ich musste.)

Hoffnung, die Ihnen einen kleinen Einblick gibt.

Andere Tipps

Wir verwenden solr eine große Produkt-Datenbank abzufragen. Rund 1 Million Produkte und 30 speichert.

Was wir getan haben ist, dass wir verwenden Trigger für die Produkttabelle und Bestandstabellen auf unseren SQLServer.

Jedes Mal, wenn eine Zeile wird flags das Produkt verändert indexiert werden. Und wir haben einen Windows-Dienst, die diese Produkte packen und nach ihnen alle 10 Sekunden Solr. (Mit einer Grenze von 100 Produkten pro Charge).

Es ist super effizient, fast in Echtzeit Informationen für die Aktie.

Wenn Sie ein großes Textfeld (Ihre ‚Körper‘ Feld) haben, dann ja, re-Index im Hintergrund. Die Lösungen, die Sie erwähnen (Warteschlange oder periodischer Hintergrunddienst) tun werden.

MVC-Controller sollten diesen Prozess nicht bewusst sein.

ich bemerkt, dass Sie IQueryables in Ihrem Repository-Schnittstelle verfügen. SolrNet derzeit nicht Haben Sie einen LINQ-Anbieter . Wie auch immer, wenn diese Operationen alle sind Sie mit Solr tun (das heißt keine Facettierung) gehen, mögen Sie vielleicht stattdessen mit Lucene.Net betrachten, die nicht einen LINQ-Provider hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top