Ein einfacher, aber leistungsstarker Ruby-Wrapper für RediSearch, eine Suchmaschine auf Redis.
Zunächst müssen Redis und RediSearch installiert werden.
Sie können Redis von https://redis.io/download herunterladen und die Installationsanweisungen hier lesen. Alternativ können Sie unter macOS oder Linux auch über Homebrew installieren.
Um RediSearch zu installieren, schauen Sie sich https://oss.redislabs.com/redisearch/Quick_Start.html an. Sobald Sie RediSearch erstellt haben und Docker nicht verwenden, können Sie Ihre redis.conf-Datei aktualisieren, um das RediSearch-Modul immer mit loadmodule /path/to/redisearch.so
zu laden. (Unter macOS finden Sie die Datei redis.conf unter /usr/local/etc/redis.conf
.)
Nachdem Redis und RediSearch betriebsbereit sind, fügen Sie die folgende Zeile zu Ihrer Gemfile hinzu:
gem 'redi_search'
Und dann:
❯ bundle
Oder installieren Sie es selbst:
❯ gem install redi_search
und verlangen es:
require 'redi_search'
Sobald das Gem installiert und erforderlich ist, müssen Sie es mit Ihrer Redis-Konfiguration konfigurieren. Wenn Sie Rails verwenden, sollte dies in einen Initialisierer ( config/initializers/redi_search.rb
) eingefügt werden.
RediSearch . configure do | config |
config . redis_config = {
host : "127.0.0.1" ,
port : "6379"
}
end
RediSearch dreht sich um einen Suchindex. Beginnen wir also mit der Definition, was ein Suchindex ist. Laut Swiftype:
Ein Suchindex ist ein Körper strukturierter Daten, auf den eine Suchmaschine zurückgreift, wenn sie nach Ergebnissen sucht, die für eine bestimmte Suchanfrage relevant sind. Indizes sind ein wichtiger Bestandteil jedes Suchsystems, da sie auf die spezifische Informationsabrufmethode des Algorithmus der Suchmaschine zugeschnitten sein müssen. Auf diese Weise sind Algorithmus und Index untrennbar miteinander verbunden. Index kann auch als Verb (Indexierung) verwendet werden und bezieht sich auf den Prozess des Sammelns unstrukturierter Website-Daten in einem strukturierten Format, das auf den Suchmaschinenalgorithmus zugeschnitten ist.
Eine Möglichkeit, über Indizes nachzudenken, besteht darin, die folgende Analogie zwischen einer Suchinfrastruktur und einem Büroablagesystem zu betrachten. Stellen Sie sich vor, Sie geben einem Praktikanten einen Stapel tausender Zettel (Dokumente) und fordern ihn auf, diese Zettel in einem Aktenschrank (Register) zu ordnen, damit das Unternehmen Informationen effizienter finden kann. Der Praktikant muss zunächst die Papiere durchsehen und sich einen Überblick über alle darin enthaltenen Informationen verschaffen, dann muss er sich für ein System zum Ordnen der Unterlagen im Aktenschrank entscheiden und schließlich muss er entscheiden, was das ist Dies ist die effektivste Methode zum Durchsuchen und Auswählen der Dateien, sobald sie sich im Schrank befinden. In diesem Beispiel entspricht der Prozess des Organisierens und Ablegens der Dokumente dem Prozess der Indizierung von Website-Inhalten, und die Methode zum Durchsuchen dieser organisierten Dateien und zum Finden der relevantesten Dateien entspricht dem Suchalgorithmus.
Dadurch werden die Felder und die Eigenschaften dieser Felder im Index definiert. Ein Schema ist ein einfaches DSL. Jedes Feld kann einen von vier Typen haben: Geo, Numerisch, Tag oder Text und kann viele Optionen haben. Ein einfaches Beispiel für ein Schema ist:
RediSearch :: Schema . new do
text_field :first_name
text_field :last_name
end
Die unterstützten Optionen für jeden Typ sind wie folgt:
Ohne Optionen: text_field :name
text_field :name, weight: 2
text_field :name, phonetic: 'dm:en'
text_field :name, sortable: true
sortable
nützlich, um Felder zu erstellen, deren Aktualisierung mit PARTIAL nicht zu einer vollständigen Neuindizierung des Dokuments führt. Wenn ein Feld no_index
und nicht sortable
hat, wird es vom Index einfach ignoriert.text_field :name, no_index: true
text_feidl :name, no_stem: true
Ohne Optionen: numeric_field :price
numeric_field :id, sortable: true
sortable
nützlich, um Felder zu erstellen, deren Aktualisierung mit PARTIAL nicht zu einer vollständigen Neuindizierung des Dokuments führt. Wenn ein Feld no_index
und nicht sortable
hat, wird es vom Index einfach ignoriert.numeric_field :id, no_index: true
Ohne Optionen: tag_field :tag
tag_field :tag, sortable: true
sortable
nützlich, um Felder zu erstellen, deren Aktualisierung mit PARTIAL nicht zu einer vollständigen Neuindizierung des Dokuments führt. Wenn ein Feld no_index
und nicht sortable
hat, wird es vom Index einfach ignoriert.tag_field :tag, no_index: true
tag_field :tag, separator: ','
Ohne Optionen: geo_field :place
geo_field :place, sortable: true
sortable
nützlich, um Felder zu erstellen, deren Aktualisierung mit PARTIAL nicht zu einer vollständigen Neuindizierung des Dokuments führt. Wenn ein Feld no_index
und nicht sortable
hat, wird es vom Index einfach ignoriert.geo_field :place, no_index: true
Ein Document
ist die Ruby-Darstellung eines Redis-Hashs.
Sie können ein Document
mit den Methoden .get
Klasse abrufen.
get(index, document_id)
ruft ein einzelnes Document
in einem Index
für eine bestimmte document_id
ab. Sie können eine Document
Instanz auch mit der Klassenmethode .for_object(index, record, only: [])
erstellen. Es benötigt eine Index
und ein Ruby-Objekt. Dieses Objekt muss auf alle im Schema
des Index
angegebenen Felder reagieren. akzeptiert only
ein Array von Feldern aus dem Schema und begrenzt die Felder, die an das Document
übergeben werden.
Sobald Sie eine Instanz eines Document
haben, reagiert es auf alle Felder, die im Schema
des Index
als Methoden und document_id
angegeben sind. document_id
wird automatisch der Name des Index
vorangestellt, es sei denn, dies ist bereits geschehen, um die Eindeutigkeit sicherzustellen. Wir stellen den Index
voran, denn wenn Sie zwei Document
s mit derselben ID in unterschiedlichen Index
s haben, möchten wir nicht, dass sich die Document
s gegenseitig überschreiben. Es gibt auch eine #document_id_without_index
-Methode, die den vorangestellten Indexnamen entfernt.
Schließlich gibt es eine #del
-Methode, die das Document
aus dem Index
entfernt.
Um einen Index
zu initialisieren, übergeben Sie den Namen des Index
als Zeichenfolge oder Symbol und den Schema
Block.
RediSearch :: Index . new ( name_of_index ) do
text_field :foobar
end
create
false
zurück, wenn der Index bereits vorhanden ist. Akzeptiert einige Optionen:max_text_fields: #{true || false}
add_field
zusätzliche Felder (über 32 hinaus) hinzufügen können.no_offsets: #{true || false}
no_highlight
.temporary: #{seconds}
seconds
der Inaktivität abläuft. Der interne Leerlauf-Timer wird jedes Mal zurückgesetzt, wenn der Index durchsucht oder hinzugefügt wird. Da solche Indizes leichtgewichtig sind, können Sie Tausende solcher Indizes ohne negative Auswirkungen auf die Leistung erstellen.no_highlight: #{true || false}
no_highlight
wird auch von no_offsets
impliziert.no_fields: #{true || false}
no_frequencies: #{true || false}
drop(keep_docs: false)
Index
aus der Redis-Instanz und gibt einen booleschen Wert zurück. Verfügt über eine zugehörige Bang-Methode, die bei einem Fehler eine Ausnahme auslöst. Gibt false
zurück, wenn der Index
bereits gelöscht wurde. Akzeptiert ein Optionsschlüsselwort arg, keep_docs
, das standardmäßig alle Dokument-Hashes in Redis entfernt.exist?
Index
angibt.info
Index
zurück.fields
Index
zurück.add(document)
Document
Objekt. Verfügt über eine zugehörige Bang-Methode, die bei einem Fehler eine Ausnahme auslöst.add_multiple(documents)
Document
Objekten. Dies bietet eine leistungsfähigere Möglichkeit, mehrere Dokumente zum Index
hinzuzufügen. Akzeptiert die gleichen Optionen wie add
.del(document)
Document
aus dem Index
.document_count
Document
s im Index
zurückadd_field(name, type, **options, &block)
Index
ein neues Feld hinzu.index.add_field(:first_name, :text, phonetic: "dm:en")
reindex(documents, recreate: false)
recreate
true
ist, wird der Index
gelöscht und neu erstellt Die Suche wird von einer RediSearch::Index
Instanz mit Klauseln initiiert, die miteinander verkettet werden können. Bei der Suche wird ein Array von Document
s zurückgegeben, das über öffentliche Lesemethoden für alle Schemafelder verfügt.
main ❯ index = RediSearch :: Index . new ( "user_idx" ) { text_field :name , phonetic : "dm:en" }
main ❯ index . add RediSearch :: Document . for_object ( index , User . new ( "10039" , "Gene" , "Volkman" ) )
main ❯ index . add RediSearch :: Document . for_object ( index , User . new ( "9998" , "Jeannie" , "Ledner" ) )
main ❯ index . search ( "john" )
RediSearch ( 1.1 ms ) FT . SEARCH user_idx `john`
=> [ #<RediSearch::Document:0x00007f862e241b78 first: "Gene", last: "Volkman", document_id: "10039">,
#<RediSearch::Document:0x00007f862e2417b8 first: "Jeannie", last: "Ledner", document_id: "9998">]
Einfache Phrasenabfrage – hello AND world
index . search ( "hello" ) . and ( "world" )
Genaue Phrasenabfrage – hello FOLLOWED BY world
index . search ( "hello world" )
Union-Abfrage – hello OR world
index . search ( "hello" ) . or ( "world" )
Negationsabfrage – hello AND NOT world
index . search ( "hello" ) . and . not ( "world" )
Komplexe Schnittmengen und Vereinigungen:
# Intersection of unions
index . search ( index . search ( "hello" ) . or ( "halo" ) ) . and ( index . search ( "world" ) . or ( "werld" ) )
# Negation of union
index . search ( "hello" ) . and . not ( index . search ( "world" ) . or ( "werld" ) )
# Union inside phrase
index . search ( "hello" ) . and ( index . search ( "world" ) . or ( "werld" ) )
Alle Begriffe unterstützen einige Optionen, die angewendet werden können.
Präfixbegriffe : Übereinstimmung mit allen Begriffen, die mit einem Präfix beginnen. (Ähnlich wie like term%
in SQL)
index . search ( "hel" , prefix : true )
index . search ( "hello worl" , prefix : true )
index . search ( "hel" , prefix : true ) . and ( "worl" , prefix : true )
index . search ( "hello" ) . and . not ( "worl" , prefix : true )
Optionale Begriffe : Dokumente, die die optionalen Begriffe enthalten, werden höher eingestuft als solche ohne
index . search ( "foo" ) . and ( "bar" , optional : true ) . and ( "baz" , optional : true )
Unscharfe Begriffe : Übereinstimmungen werden basierend auf der Levenshtein-Distanz (LD) durchgeführt. Die maximal unterstützte Levenshtein-Distanz beträgt 3.
index . search ( "zuchini" , fuzziness : 1 )
Suchbegriffe können mithilfe einer where
-Klausel auch auf bestimmte Felder beschränkt werden:
# Simple field specific query
index . search . where ( name : "john" )
# Using where with options
index . search . where ( first : "jon" , fuzziness : 1 )
# Using where with more complex query
index . search . where ( first : index . search ( "bill" ) . or ( "bob" ) )
Die Suche nach numerischen Feldern erfordert einen Bereich:
index . search . where ( number : 0 .. 100 )
# Searching to infinity
index . search . where ( number : 0 .. Float :: INFINITY )
index . search . where ( number : - Float :: INFINITY .. 0 )
slop(level)
in_order
slop
verwendet. Wir stellen sicher, dass die Abfragebegriffe im Document
in derselben Reihenfolge wie in der Abfrage erscheinen, unabhängig von den Versätzen zwischen ihnen.no_content
Document
-IDs und nicht den Inhalt zurück. Dies ist nützlich, wenn RediSearch in einem Rails-Modell verwendet wird, bei dem die Document
keine Rolle spielen und es in ActiveRecord
Objekte konvertiert wird.language(language)
Document
auf Chinesisch abgefragt werden, sollte dies auf Chinesisch eingestellt werden, um die Abfragebegriffe ordnungsgemäß zu tokenisieren. Wenn eine nicht unterstützte Sprache gesendet wird, gibt der Befehl einen Fehler zurück.sort_by(field, order: :asc)
:asc
oder :desc
limit(num, offset = 0)
num
am offset
. Der Standardgrenzwert ist auf 10
eingestellt.count
Document
zurückhighlight(fields: [], opening_tag: "<b>", closing_tag: "</b>")
fields
sind eine Reihe von Feldern, die hervorgehoben werden sollen.verbatim
no_stop_words
with_scores
Document
an. Dies kann verwendet werden, um Ergebnisse aus mehreren Instanzen zusammenzuführen. Dadurch wird den zurückgegebenen Document
eine score
hinzugefügt.return(*fields)
Document
zurückgegeben werden.explain
Die Rechtschreibprüfung wird von einer RediSearch::Index
Instanz aus initiiert und bietet Vorschläge für falsch geschriebene Suchbegriffe. Es benötigt ein optionales distance
, das die maximale Levenshtein-Distanz für Rechtschreibvorschläge angibt. Es wird ein Array zurückgegeben, in dem jedes Element Vorschläge für jeden Suchbegriff und eine normalisierte Bewertung basierend auf seinem Vorkommen im Index enthält.
main ❯ index = RediSearch :: Index . new ( "user_idx" ) { text_field :name , phonetic : "dm:en" }
main ❯ index . spellcheck ( "jimy" )
RediSearch ( 1.1 ms ) FT . SPELLCHECK user_idx jimy DISTANCE 1
=> [ #<RediSearch::Spellcheck::Result:0x00007f805591c670
term : "jimy" ,
suggestions :
[ #<struct RediSearch::Spellcheck::Suggestion score=0.0006849315068493151, suggestion="jimmy">,
#<struct RediSearch::Spellcheck::Suggestion score=0.00019569471624266145, suggestion="jim">]>]
main ❯ index . spellcheck ( "jimy" , distance : 2 ) . first . suggestions
RediSearch ( 0.5 ms ) FT . SPELLCHECK user_idx jimy DISTANCE 2
=> [ #<struct RediSearch::Spellcheck::Suggestion score=0.0006849315068493151, suggestion="jimmy">,
#<struct RediSearch::Spellcheck::Suggestion score=0.00019569471624266145, suggestion="jim">]
Die Integration mit Rails ist super einfach! Rufen Sie redi_search
mit dem schema
Schlüsselwortargument aus Ihrem Modell heraus auf. Ex:
class User < ApplicationRecord
redi_search do
text_field :first , phonetic : "dm:en"
text_field :last , phonetic : "dm:en"
end
end
Dadurch werden automatisch die Methoden User.search
und User.spellcheck
hinzugefügt, die sich genauso verhalten, als ob Sie sie auf einer Index
aufgerufen hätten.
User.reindex(recreate: false, only: [])
wird ebenfalls hinzugefügt und verhält sich ähnlich wie RediSearch::Index#reindex
. Zu den Unterschieden gehören:
Document
s müssen nicht als erster Parameter übergeben werden. Der Bereich search_import
wird automatisch aufgerufen und alle Datensätze werden in Document
s konvertiert.only
optionalen Parameter, mit dem Sie eine begrenzte Anzahl von zu aktualisierenden Feldern angeben können. Nützlich, wenn Sie das Schema ändern und nur ein bestimmtes Feld indizieren müssen. Beim Definieren des Schemas können Sie ihm optional einen Block übergeben. Wenn kein Block übergeben wird, wird der name
im Modell aufgerufen, um den Wert abzurufen. Wenn ein Block übergeben wird, wird der Wert für das Feld durch den Aufruf des Blocks erhalten.
class User < ApplicationRecord
redi_search do
text_field :name do
" #{ first_name } #{ last_name } "
end
end
end
Sie können den Suchbereich search_import
im Modell überschreiben, um Beziehungen beim Indizieren zu laden, oder er kann verwendet werden, um die zu indizierenden Datensätze einzuschränken.
class User < ApplicationRecord
scope :search_import , -> { includes ( :posts ) }
end
Bei der Suche wird standardmäßig eine Sammlung von Document
s zurückgegeben. Der Aufruf von #results
für die Suchabfrage führt die Suche aus, sucht dann nach allen gefundenen Datensätzen in der Datenbank und gibt eine ActiveRecord-Beziehung zurück.
Der Index
für Index
ist #{model_name.plural}_#{RediSearch.env}
. Die redi_search
-Methode akzeptiert ein optionales index_prefix
-Argument, das dem Indexnamen vorangestellt wird:
class User < ApplicationRecord
redi_search index_prefix : 'prefix' do
text_field :first , phonetic : "dm:en"
text_field :last , phonetic : "dm:en"
end
end
User . search_index . name
# => prefix_users_development
Bei der Integration von RediSearch in ein Modell werden Datensätze nach der Erstellung und Aktualisierung automatisch indiziert und nach der Zerstörung aus dem Index
entfernt.
Es gibt noch einige weitere praktische Methoden, die öffentlich verfügbar sind:
search_document
RediSearch::Document
Instanz zurückremove_from_index
Index
add_to_index
Index
hinzusearch_index
RediSearch::Index
Instanz zurück Führen Sie nach dem Auschecken des Repos bin/setup
aus, um Abhängigkeiten zu installieren. Führen Sie dann rake test
aus, um sowohl den Unit- als auch den Integrationstest durchzuführen. Um sie einzeln auszuführen, können Sie rake test:unit
oder rake test:integration
ausführen. Sie können auch bin/console
ausführen, um eine interaktive Eingabeaufforderung zu erhalten, mit der Sie experimentieren können.
Um dieses Juwel auf Ihrem lokalen Computer zu installieren, führen Sie bundle exec rake install
aus. Um eine neue Version zu veröffentlichen, führen Sie bin/publish (major|minor|patch)
aus, wodurch die Versionsnummer in version.rb
aktualisiert wird, ein Git-Tag für die Version erstellt, Git-Commits und -Tags gepusht werden und die .gem
Datei an rubygems gepusht wird .org und GitHub.
Fehlerberichte und Pull-Requests sind auf GitHub willkommen. Dieses Projekt soll ein sicherer, einladender Raum für die Zusammenarbeit sein, und von den Mitwirkenden wird erwartet, dass sie sich an den Verhaltenskodex der Mitwirkendenvereinbarung halten.
Das Juwel ist als Open Source unter den Bedingungen der MIT-Lizenz verfügbar.
Von jedem, der in den Codebasen, Issue-Trackern, Chatrooms und Mailinglisten des RediSearch-Projekts interagiert, wird erwartet, dass er den Verhaltenskodex befolgt.