2013-07-02 12 views
6

Ich möchte einige Rückmeldungen und Vorschläge zu zwei Ansätzen erhalten, die ich in Erwägung ziehe, durchsuchbare Indizes mit Redis sortierten Sätzen zu implementieren.Indizierung mit Redis sortierten Sätzen

Situation und Zielsetzung

Wir haben derzeit einige Schlüssel-Wert-Tabellen wir in Cassandra sind zu speichern, und die möchten wir für Indizes haben. Zum Beispiel würde eine Tabelle Datensätze von Personen enthalten, und die Kassandra-Tabelle hätte eine ID als Primärschlüssel und das serialisierte Objekt als Wert. Das Objekt hätte Felder wie Vorname, Nachname, Letzte_aktualisiert und andere.

Was wir wollen, ist in der Lage zu tun wie "last_name = 'Smith' AND first_name> 'Joel'", "last_name < 'Aaronson'", "last_name = 'Smith' UND first_name = 'Winston' " und so weiter. Die Suchen sollten die IDs von Übereinstimmungen ergeben, damit wir die Objekte von Cassandra abrufen können. Ich denke, dass die obigen Suchen mit einem einzigen Index durchgeführt werden könnten, der lexikografisch nach last_name, first_name und last_updated sortiert ist. Wenn wir einige Suchen unter Verwendung einer anderen Reihenfolge benötigen (z. B. "first_name = 'Zeus'"), können wir einen ähnlichen Index haben, der diese erlauben würde (z. B. Vorname, Nachname_aktualisiert).

Wir betrachten Redis dafür, weil wir in der Lage sein müssen, eine große Anzahl von Schreibvorgängen pro Minute zu verarbeiten. Ich habe auf einige gemeinsame Wege nachlesen Redis-Sets verwendet werden sortiert, und kommen mit zwei möglichen Implementierungen:

Option 1: eine einzige sortierte Menge pro Index

Für unseren Index von nachname, vorname, last_updated, hätten wir einen sortierten Satz in Redis unter den Schlüsselindizes: people: last_name: first_name: last_updated, der Strings mit dem Format last_name enthalten würde: first_name: last_updated: id. Zum Beispiel:

Schmied: joel: 1372761839,444: 0azbjZRHTQ6U8enBw6BJBw

(Für den Separator könnte ich ‚::‘ anstatt ‚:‘ oder etwas anderes besser mit der lexikographischen Ordnung arbeiten, aber lassen sie das ignoriert für jetzt) ​​

Die Items würden alle mit 0 bewertet, so dass der sortierte Satz einfach lexikografisch durch die Strings selbst sortiert wird. Wenn ich dann eine Abfrage wie "last_name = 'smith' AND first_name < 'bob'" machen möchte, müsste ich alle Elemente in der Liste abrufen, die vor 'smith: bob' stehen.

Soweit ich das beurteilen kann, gibt es die folgenden Nachteile dieses Ansatzes:

  1. Es gibt keine Redis Funktion einen Bereich auf der String-Wert basierend auszuwählen. Diese Funktion namens ZRANGEBYLEX wurde von Salvatore Sanfilippo unter https://github.com/antirez/redis/issues/324 vorgeschlagen, ist aber nicht implementiert. Daher müsste ich die Endpunkte mit binären Suchvorgängen suchen und den Bereich selbst erhalten (vielleicht mit Lua oder auf Anwendungsebene mit Python) ist die Sprache, die wir verwenden, um auf Redis zuzugreifen).
  2. Wenn wir eine Time-to-live für Indexeinträge einfügen möchten, scheint es der einfachste Weg zu sein, eine regelmäßig geplante Aufgabe zu haben, die den gesamten Index durchläuft und abgelaufene Elemente entfernt.

Option 2: kleine sortierte Sätze sortiert, von last_updated

Dieser Ansatz würde ähnlich sein, es sei denn wir haben viele würden, kleiner, sortiert Sets mit jeweils einer Zeitähnlichen Wert wie LAST_UPDATED für die Noten. Zum Beispiel hätten wir für den gleichen last_name, first_name, last_updated-Index eine sortierte Menge für jede last_name, first_name-Kombination. Zum Beispiel könnte der Schlüssel ein Index sein: people: last_name = smith: first_name = joel, und er hätte einen Eintrag für jede Person, die wir Joel Smith genannt haben. Jeder Eintrag hätte den Namen id und sein Ergebnis den Wert last_updated. Z.B .:

Wert: 0azbjZRHTQ6U8enBw6BJBw; score: 1372761839.444

Die wichtigsten Vorteile hiervon sind (a) sucht, wo wir alle Felder außer last_updated wissen wäre sehr einfach, und (b) ein Time-to-Live-Umsetzung wäre sehr einfach, die ZREMRANGEBYSCORE verwenden.

Der Nachteil, der mir sehr groß erscheint, ist:

  1. Es scheint viel mehr Komplexität bei der Verwaltung und die Suche auf diese Weise zu sein. Zum Beispiel müssten wir den Index behalten, um alle seine Schlüssel zu verfolgen (in dem Fall, dass wir zum Beispiel irgendwann aufräumen wollen) und dies in einer hierarchischen Weise tun. Eine Suche wie „last_name <‚smith‘“ würde zuerst erfordern in der Liste aller Nachnamen suchen diejenigen, die kommen, bevor smith, dann für jeden der an allen Vornamen für jeden der es enthält, dann suchen zu finden alle Elemente aus der sortierten Menge erhalten. Mit anderen Worten, eine Menge von Komponenten aufzubauen und sich Sorgen zu machen.

Wrapping up

mir So scheint es die erste Option besser, trotz seiner Nachteile wäre. Ich würde mich sehr über Feedback zu diesen beiden oder anderen möglichen Lösungen freuen (selbst wenn wir etwas anderes als Redis verwenden sollten).

Antwort

7
  1. Ich rate dringend davon ab, Redis dafür zu verwenden. Sie erhalten eine Tonne zusätzliche Zeigerdaten werden zu speichern, und wenn Sie jemals entscheiden Sie, kompliziertere Anfragen tun wollen wie, SELECT WHERE first_name LIKE 'jon%' Sie gehen in Schwierigkeiten geraten. Sie müssen auch zusätzliche, sehr große Indizes erstellen, die sich über mehrere Spalten erstrecken, falls Sie nach zwei Feldern gleichzeitig suchen möchten. Sie müssen im Wesentlichen weiterhin ein Suchframework hacken und neu gestalten. Sie würden viel besser dran mit Elastic Search oder Solr, oder einen der anderen Frameworks bereits gebaut zu tun, was Sie versuchen zu tun. Redis ist großartig und hat viele gute Anwendungen. Dies ist keiner von ihnen.

  2. Warnung beiseite, Ihre eigentliche Frage zu beantworten: Ich glaube, Sie am besten mit einer Variante der ersten Lösung bedient werden würden. Verwenden Sie eine einzelne sortierte Menge pro Index, aber konvertieren Sie einfach Ihre Buchstaben in Zahlen. Konvertiere deine Buchstaben in einen Dezimalwert. Sie können den ASCII-Wert verwenden oder jedem Buchstaben in lexikographischer Reihenfolge einen Wert von 1-26 zuweisen, vorausgesetzt, Sie verwenden Englisch. Standardisieren, so dass jeder Buchstabe die gleiche numerische Länge (also, wenn 26 Ihre größte Nummer ist, würde 1 "01" geschrieben werden). Dann fügen Sie diese zusammen mit einem Dezimalpunkt vor und verwenden Sie das als Ihre Punktzahl pro Index (d. H. "Hut" wäre ".080120"). Auf diese Weise erhalten Sie eine ordnungsgemäß geordnete 1-zu-1-Zuordnung zwischen Wörtern und diesen Zahlen. Wenn Sie suchen, von Buchstaben in Zahlen, konvertieren und dann werden Sie in der Lage sein, wie ZRANGEBYSCORE alle Redis' schön sortierten Satz Funktionen zu verwenden, ohne sie neu schreiben zu müssen.Redis 'Funktionen sind sehr, sehr optimal geschrieben, so dass Sie sie viel besser nutzen können, wenn Sie das können, anstatt selbst zu schreiben.

4

Sie könnten mein Projekt python-stdnet dafür verwenden, es macht die ganze Indizierung für Sie. Zum Beispiel:

class Person(odm.StdModel): 
    first_name = odm.SymbolField() 
    last_name = odm.SymbolField() 
    last_update = odm.DateTimeField() 

Sobald ein Modell registered with a redis backend ist, können Sie dies tun:

qs = models.person.filter(first_name='john', last_name='smith') 

sowie

qs = models.person.filter(first_name=('john','carl'), last_name=('smith','wood')) 

und vieles mehr

Die Filterung ist schnell da alle IDs bereits in Sätzen sind.

+0

Die [Hilfe wie kein Spammer sein] (http://stackoverflow.com/help/promotion) ist klar, dass „Sie Ihre Zugehörigkeit in Ihren Antworten offen legen müssen.“ Ich habe deine Antwort entsprechend bearbeitet. – Louis

0

Sie können redblade überprüfen, es kann Wartungsindex automatisch für Sie und es wird von Node.JS geschrieben.

//define schema 
redblade.schema('article', { 
    "_id"   : "id" 
    , "poster"  : "index('user_article')" 
    , "keywords" : "keywords('articlekeys', return +new Date()/60000 | 0)" 
    , "title"  : "" 
    , "content"  : "" 
}) 


//insert an article 
redblade.insert('article', { 
    _id  : '1234567890' 
    , poster  : 'airjd' 
    , keywords : '信息技术,JavaScript,NoSQL' 
    , title  : '测试用的SLIDE 标题' 
    , content : '测试用的SLIDE 内容' 
}, function(err) { 

}) 


//select by index field or keywords 
redblade.select('article', { poster:'airjd' }, function(err, articles) { 
    console.log(articles[0]) 
}) 

redblade.select('article', { keywords: 'NoSQL' }, function(err, articles) { 
    console.log(articles[0]) 
}) 
Verwandte Themen