In diesem Artikel zeige ich Ihnen, wie Sie die Volltextsuche mit Ruby on Rails und Elasticsearch implementieren. Heutzutage ist es jeder gewohnt, einen Suchbegriff einzugeben und Vorschläge und hervorgehobene Ergebnisse für den Suchbegriff zu erhalten. Die Autokorrektur ist auch eine nette Funktion, wenn das, wonach Sie suchen, falsch geschrieben ist, wie wir auf Websites wie Google oder Facebook gesehen haben.
Alle diese Funktionen nur mit einer relationalen Datenbank wie MySQL oder Postgres zu erreichen, ist nicht einfach. Deshalb verwenden wir Elasticsearch, eine Datenbank, die speziell für die Suche erstellt und optimiert wurde. Es ist Open Source und basiert auf Apache Lucene.
Eine der besten Funktionen von Elasticsearch ist die Bereitstellung seiner Funktionalität mithilfe einer REST-API. Daher gibt es Bibliotheken, die diese Funktionalität für die meisten Programmiersprachen kapseln.
Zuvor habe ich erwähnt, dass Elasticsearch wie eine Datenbank zum Suchen ist. Dies ist nützlich, wenn Sie mit einigen seiner Terminologien vertraut sind.
Hier ist zu beachten, dass in Elasticsearch beim Schreiben eines Dokuments in den Index die Dokumentfelder wörtlich analysiert werden, um die Suche einfach und schnell zu machen. Elasticsearch unterstützt auch die Geolokalisierung, sodass Sie nach Dokumenten suchen können, die sich in einer bestimmten Entfernung von einem bestimmten Standort befinden. Genau so implementiert Foursquare die Suche.
Ich möchte erwähnen, dass Elasticsearch auf hohe Skalierbarkeit ausgelegt ist, sodass es einfach ist, Cluster mit mehreren Servern aufzubauen und eine hohe Verfügbarkeit zu gewährleisten, selbst wenn einige Server ausfallen. Ich werde in diesem Artikel nicht näher auf die Planung und Bereitstellung verschiedener Clustertypen eingehen.
Wenn Sie Linux verwenden, können Sie Elasticsearch möglicherweise aus einem der Repositorys installieren. Es kann in APT und YUM verwendet werden.
Wenn Sie einen Mac verwenden, können Sie ihn mit Homebrew installieren: brew install elasticsearch
. Nach der Installation von Elasticsearch sehen Sie im Terminal eine Liste der zugehörigen Ordner:
Um zu überprüfen, ob die Installation funktioniert, geben Sie elasticsearch
来启动它。然后在终端中运行 curl localhost:9200
in das Terminal ein und Sie sollten etwas Ähnliches wie das Folgende sehen:
Elastic HQ ist ein Überwachungs-Plugin, mit dem wir Elasticsearch über den Browser verwalten können, ähnlich wie phpMyAdmin für MySQL. Um es zu installieren, führen Sie einfach Folgendes im Terminal aus:
/usr/local/Cellar/elasticsearch/2.2.0_1/libexec/bin/plugin -install royrusso/elasticsearch-HQ
Nach Abschluss der Installation navigieren Sie in Ihrem Browser zu http://localhost:9200/_plugin/hq:
Klicken Sie auf Verbinden und Sie sehen einen Bildschirm mit dem Clusterstatus: p>
Zu diesem Zeitpunkt wurden erwartungsgemäß noch keine Indizes oder Dokumente erstellt, aber wir haben eine lokale Instanz von Elasticsearch installiert und ausgeführt.
Ich werde eine sehr einfache Rails-Anwendung erstellen, in der Sie Artikel zu einer Datenbank hinzufügen, damit wir mit Elasticsearch Volltextsuchen darauf durchführen können. Beginnen Sie mit der Erstellung einer neuen Rails-Anwendung:
rails 新的 elasticsearch-rails
Als nächstes verwenden wir Gerüste, um eine neue Artikelressource zu generieren:
rails生成脚手架文章标题:string text:text
Jetzt müssen wir eine neue Root-Route hinzufügen, damit wir die Artikelliste standardmäßig sehen können. Bearbeiten Sie config/routes.rb:
Rails.application.routes.draw do root to: 'articles#index' resources :articles end
Öffnen Sie einen Browser, indem Sie den Befehl rake db:migrate
创建数据库。如果您启动 rails server
ausführen, navigieren Sie zu localhost:3000 und fügen Sie einige Artikel zur Datenbank hinzu oder laden Sie einfach die Datei db/seeds.rb mit den von mir erstellten Dummy-Daten herunter, damit Sie nicht viel ausgeben müssen Zeit für das Ausfüllen von Formularen.
Da wir nun unsere kleine Rails-App haben, die die Artikel in der Datenbank enthält, können wir Suchfunktionen hinzufügen. Wir beginnen mit dem Hinzufügen von Verweisen auf zwei offizielle Elasticsearch-Gems:
gem 'elasticsearch-model' gem 'elasticsearch-rails'
Auf vielen Websites ist es üblich, im oberen Menü aller Seiten ein Textfeld für die Suche zu haben. Deshalb werde ich unter app/views/search/_form.html.erb einen Formularabschnitt erstellen. Wie Sie sehen, sende ich das generierte Formular mit GET, damit es einfach ist, die URL für eine bestimmte Suche zu kopieren und einzufügen.
<%= form_for :term, url: search_path, method: :get do |form| %> <p> <%= text_field_tag :term, params[:term] %> <%= submit_tag "Search", name: nil %> </p> <% end %>
Fügen Sie im Haupt-Website-Layout einen Verweis auf das Formular hinzu. Bearbeiten Sie app/views/layouts/application.html.erb.
<body> <%= render 'search/form' %> <%= yield %> </body>
Jetzt benötigen wir auch einen Controller, um die eigentliche Suche durchzuführen und die Ergebnisse anzuzeigen, also führen wir den Befehl rails g 新控制器 Search
aus, um ihn zu generieren.
class SearchController < ApplicationController def search if params[:term].nil? @articles = [] else @articles = Article.search params[:term] end end end
Wie Sie sehen können, rufe ich die Methode search
im Article-Modell auf. Wir haben es noch nicht definiert. Wenn wir also an dieser Stelle versuchen, eine Suche durchzuführen, erhalten wir eine Fehlermeldung. Außerdem haben wir die Routen des SearchControllers nicht in der Datei config/routes.rb hinzugefügt, also machen wir Folgendes:
Rails.application.routes.draw do root to: 'articles#index' resources :articles get "search", to: "search#search" end
Wenn wir uns die Dokumentation für das Gem 'elasticsearch-rails' ansehen, müssen wir zwei Module in das Modell einbinden, das in Elasticsearch indiziert werden soll, in unserem Fall article.rb.
require 'elasticsearch/model' class Article < ActiveRecord::Base include Elasticsearch::Model include Elasticsearch::Model::Callbacks end
Das erste Modell fügt die Suchmethode ein, die wir im vorherigen Controller verwendet haben. Das zweite Modul ist in ActiveRecord-Rückrufe integriert, um jede Instanz eines Artikels zu indizieren, die wir in der Datenbank speichern, und aktualisiert den Index auch, wenn wir einen Artikel ändern oder aus der Datenbank löschen. Für uns ist also alles transparent.
Wenn Sie zuvor Daten in die Datenbank importiert haben, sind diese Artikel immer noch nicht im Elasticsearch-Index; nur neue werden automatisch indiziert. Daher müssen wir sie manuell indizieren, was beim Starten in Ordnung ist rails console
就很容易。然后我们只需要运行 irb(main) > Article.import
.
Jetzt sind wir bereit, die Suchfunktion auszuprobieren. Wenn ich „ruby“ eingebe und auf „Suchen“ klicke, sind hier die Ergebnisse:
Auf vielen Websites können Sie sehen, wie die von Ihnen gesuchten Begriffe auf der Suchergebnisseite hervorgehoben werden. Mit Elasticsearch geht das ganz einfach.
Bearbeiten Sie app/models/article.rb und ändern Sie die Standardsuchmethode:
def self.search(query) __elasticsearch__.search( { query: { multi_match: { query: query, fields: ['title', 'text'] } }, highlight: { pre_tags: ['<em>'], post_tags: ['</em>'], fields: { title: {}, text: {} } } } ) end
Standardmäßig wird die search
-Methode durch gem „elasticsearch-models“ definiert und stellt das Proxy-Objekt __elasticsearch__ bereit, um auf die Wrapper-Klasse der Elasticsearch-API zuzugreifen. Daher können wir die Standardabfrage mithilfe der in der Dokumentation bereitgestellten Standard-JSON-Optionen ändern.
Die Suchmethode umschließt nun Ergebnisse, die der Abfrage entsprechen, mit dem angegebenen HTML-Tag. Dazu müssen wir auch die Suchergebnisseite aktualisieren, um HTML-Tags sicher darzustellen. Bearbeiten Sie dazu app/views/search/search.html.erb.
<h1>Search Results</h1> <% if @articles %> <ul class="search_results"> <% @articles.each do |article| %> <li> <h3> <%= link_to article.try(:highlight).try(:title) ? article.highlight.title[0].html_safe : article.title, controller: "articles", action: "show", id: article._id %> </h3> <% if article.try(:highlight).try(:text) %> <% article.highlight.text.each do |snippet| %> <p><%= snippet.html_safe %>...</p> <% end %> <% end %> </li> <% end %> </ul> <% else %> <p>Your search did not match any documents.</p> <% end %>
Fügen Sie CSS-Stile zu app/assets/stylesheets/search.scss für hervorgehobenes Markup hinzu:
.search_results em { background-color: yellow; font-style: normal; font-weight: bold; }
Versuchen Sie erneut, nach „Rubin“ zu suchen:
Wie Sie sehen, ist das Hervorheben von Suchbegriffen einfach, aber nicht ideal, da wir eine JSON-Abfrage senden müssen und wir, wie in der Elasticsearch-Dokumentation angegeben, keinerlei Abstraktion haben.
Das Searchkick-Gem wird von Instacart bereitgestellt und ist eine Abstraktion des offiziellen Elasticsearch-Gems. Ich werde die Hervorhebungsfunktion umgestalten, sodass wir zuerst gem 'searchkick'
zur Gem-Datei hinzufügen. Die erste Klasse, die wir ändern müssen, ist das Article.rb-Modell:
class Article < ActiveRecord::Base searchkick end
Wie Sie sehen, ist es viel einfacher. Wir müssen die Artikel erneut indizieren und den Befehl rake searchkick:reindex CLASS=Article
ausführen. Um Suchbegriffe hervorzuheben, müssen wir einen zusätzlichen Parameter von search_controller.rb an die Suchmethode übergeben.
class SearchController < ApplicationController def search if params[:term].nil? @articles = [] else term = params[:term] @articles = Article.search term, fields: [:text], highlight: true end end end
Die letzte Datei, die wir ändern müssen, ist views/search/search.html.erb , da Searchkick jetzt Ergebnisse in einem anderen Format zurückgibt:
<h2>Search Results for: <i><%= params[:term] %></i></h2> <% if @articles %> <ul class="search_results"> <% @articles.with_details.each do |article, details| %> <li> <h3> <%= link_to article.title, controller: "articles", action: "show", id: article.id %> </h3> <p><%= details[:highlight][:text].html_safe %>...</p> </li> <% end %> </ul> <% else %> <p>Your search did not match any documents.</p> <% end %>
Jetzt ist es an der Zeit, die App erneut auszuführen und die Suchfunktion zu testen:
请注意,我输入了搜索词“dato”。我这样做的目的是为了向您展示,默认情况下,searchkick 设置为分析索引的文本,并且更允许拼写错误。
自动建议或预先输入可预测用户将输入的内容,从而使搜索体验更快、更轻松。请记住,除非您有数千条记录,否则最好在客户端进行过滤。
让我们首先添加 typeahead 插件,该插件可通过 gem 'bootstrap-typeahead-rails'
获得,并将其添加到您的 Gemfile 中。接下来,我们需要向 app/assets/javascripts/application.js 添加一些 JavaScript,以便当您开始在搜索框中输入内容时,会出现一些建议。
//= require jquery //= require jquery_ujs //= require turbolinks //= require bootstrap-typeahead-rails //= require_tree . var ready = function() { var engine = new Bloodhound({ datumTokenizer: function(d) { console.log(d); return Bloodhound.tokenizers.whitespace(d.title); }, queryTokenizer: Bloodhound.tokenizers.whitespace, remote: { url: '../search/typeahead/%QUERY' } }); var promise = engine.initialize(); promise .done(function() { console.log('success'); }) .fail(function() { console.log('error') }); $("#term").typeahead(null, { name: "article", displayKey: "title", source: engine.ttAdapter() }) }; $(document).ready(ready); $(document).on('page:load', ready);
关于前一个片段的一些评论。在最后两行中,因为我没有禁用涡轮链接,所以这是连接我想要在页面加载时运行的代码的方法。在脚本的第一部分,您可以看到我正在使用 Bloodhound。它是 typeahead.js 建议引擎,我还设置了 JSON 端点来发出 AJAX 请求来获取建议。之后,我在引擎上调用 initialize()
,并使用其 id“term”在搜索文本字段上设置预输入。
现在,我们需要对建议进行后端实现,让我们从添加路由开始,编辑 app/config/routes.rb。
Rails.application.routes.draw do root to: 'articles#index' resources :articles get "search", to: "search#search" get 'search/typeahead/:term' => 'search#typeahead' end
接下来,我将在 app/controllers/search_controller.rb 上添加实现。
def typeahead render json: Article.search(params[:term], { fields: ["title"], limit: 10, load: false, misspellings: {below: 5}, }).map do |article| { title: article.title, value: article.id } end end
此方法返回使用 JSON 输入的术语的搜索结果。我只按标题搜索,但我也可以指定文章的正文。我还将搜索结果的数量限制为最多 10 个。
现在我们准备尝试 typeahead 实现:
如您所见,将 Elasticsearch 与 Rails 结合使用使搜索数据变得非常简单且快速。在这里,我向您展示了如何使用 Elasticsearch 提供的低级 gem,以及 Searchkick gem,这是一个隐藏了 Elasticsearch 工作原理的一些细节的抽象。
根据您的具体需求,您可能会很乐意使用 Searchkick 并快速轻松地实施全文搜索。另一方面,如果您有一些其他复杂的查询,包括过滤器或组,您可能需要了解有关 Elasticsearch 上查询语言的详细信息,并最终使用较低级别的 gem 'elasticsearch-models' 和 'elasticsearch-导轨”。
Das obige ist der detaillierte Inhalt vonVolltextsuche in Rails mit Elasticsearch. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!