#Elasticsearch without DB https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence#the-activerecord-pattern
##Задача - сделать поиск записей, которые загружаются непосредственно в Elasticsearch ##Gemfile
../Gemfile
group :development do
# отключает журнал трубопровода активов Rails (https://github.com/evrone/quiet_assets)
gem 'quiet_assets'
end
# elasticsearch without DB
gem 'simple_form'
gem 'elasticsearch', git: 'git://github.com/elasticsearch/elasticsearch-ruby.git'
gem 'elasticsearch-model', git: 'git://github.com/elasticsearch/elasticsearch-rails.git', require: 'elasticsearch/model'
gem 'elasticsearch-persistence', git: 'git://github.com/elasticsearch/elasticsearch-rails.git', require: 'elasticsearch/persistence/model'
gem 'elasticsearch-rails', git: 'git://github.com/elasticsearch/elasticsearch-rails.git'
##Настройка Elasticsearch
../app/models/document.rb
class Document
include Elasticsearch::Persistence::Model
# for custom settings (host, log, etc) persistence elasticsearch
include Elasticsearch::Persistence::Repository
client Elasticsearch::Client.new host: Rails.configuration.elasticsearch_host
...some code
end
../config/enviroments/development.rb
Rails.application.configure do
...some code
#
config.elasticsearch_prefix = 'development'
config.elasticsearch_host = '51.1.0.12'
end
##Model
../app/models/document.rb
class Document
include Elasticsearch::Persistence::Model
# for custom settings persistence elasticsearch
include Elasticsearch::Persistence::Repository
client Elasticsearch::Client.new host: Rails.configuration.elasticsearch_host
index_name "#{Rails.configuration.elasticsearch_prefix}_document"
attribute :id, Integer
attribute :title, String
attribute :description, String
settings index: { number_of_shards: 1 } do
mappings dynamic: 'false' do
indexes :id, :index => :not_analyzed, :type => 'integer'
indexes :name, :analyzer => 'standard', :boost => 100
indexes :description, :analyzer => 'standard', :boost => 50
end
end
def self.search_me(q)
q = "" if q.nil?
#
q = sanitize_string(q)
#
Document.search \
query: {
filtered: {
query:{
query_string: {
query: q + '*',
fields: ['title', 'description']
}
}
}
},
highlight: {
pre_tags: ['<em>'],
post_tags: ['</em>'],
fields: {
name: {},
description: {fragment_size: 80, number_of_fragments: 3}
}
}
end
def self.sanitize_string(str)
# Escape special characters
# http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html#Escaping Special Characters
escaped_characters = Regexp.escape('\\+-&|!(){}[]^~*?:\/')
str = str.gsub(/([#{escaped_characters}])/, '\\\\\1')
# AND, OR and NOT are used by lucene as logical operators. We need
# to escape them
['AND', 'OR', 'NOT'].each do |word|
escaped_word = word.split('').map {|char| "\\#{char}" }.join('')
str = str.gsub(/\s*\b(#{word.upcase})\b\s*/, " #{escaped_word} ")
end
# Escape odd quotes
quote_count = str.count '"'
str = str.gsub(/(.*)"(.*)/, '\1\"\3') if quote_count % 2 == 1
str
end
end
attribute :title, String
- поля, которые будут храниться в Elasticsearch- остальное см. здесь: https://gist.github.com/elvisgiv/4bfef210aa0a75135dfd3257a061083c
##Controller
../app/controllers/search_controller.rb
class SearchController < ApplicationController
def index
q = params[:q]
@items = Document.search_me(q)
end
end
##View
../app/views/search/index.html.haml
= stylesheet_link_tag "highlight_em", media: "all"
.container
%header
%h1
Document
%section#searchbox
= form_tag(search_path, :method => "get", :id => "search", :class => "my_search", :style => "margin-top: 18px;") do
= text_field_tag :q, params[:q], placeholder: "Search document", :class => "form-control"
%br
%br
- if @items
%table.table.table-striped.table-bordered.table-hover
%tr
%th #
%th Title
%th Description
- @items.each_with_hit do |item, hit|
%tr
%td
= item.id
%td
-if hit.try(:highlight).try(:title)
- hit.highlight.title.each do |snippet|
%p
= snippet.html_safe
-else
= item.title
%td
= item.description
%br
-if hit.try(:highlight).try(:description)
%b Found:<br>
- hit.highlight.description.each do |snippet|
= snippet.html_safe
%br
- else
%p The search hasn't returned any results...
##Stylesheets
../app/assets/styleshets/higlights.css.scss
em {
background-color: yellow;
}
##Create record to Elasticsearch with index
# create ONE record with index in Elasticsearch
s_html = File.read(File.join(Rails.root, 'app/views/docs_html/installation', 'install-centos.html.erb'))
text = s_html.strip_tags
Document.create id: 1, title: 'Test', description: text
s_html = File.read(File.join(Rails.root, 'app/views/docs_html/installation', 'install-centos.html.erb'))
- загружаем одну html запись из файла'install-centos.html.erb'
text = s_html.strip_tags
- метод, который убирает html тэги из текста см. нижеDocument.create id: 1, title: 'Test', description: text
- команда создания записи в Elasticsearch с автоматическим индексированием https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence#persistence
##Recreate (cleaning) ES index
# recreate (cleaning) ES index
Document.create_index! force: true
Document.create_index! force: true
- удаляет из Elasticsearch все записи и создает пустой индекс с требуемыми параметрами. В нашем случае{"settings":{"number_of_shards":1},"mappings":{ ... {"text":{"analyzer":"standard","type":"string"}}}}}
##Config http://apidock.com/rails/ActionView/Helpers/SanitizeHelper/strip_tags
../config/initializers/string.rb
class String
def strip_tags
ActionController::Base.helpers.strip_tags(self)
end
end