Skip to content

Commit f91dc9e

Browse files
committed
Elasticsearch indexing with elasticsearch-(model|rails)
1 parent aad6aed commit f91dc9e

File tree

6 files changed

+139
-0
lines changed

6 files changed

+139
-0
lines changed

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ gem "rails", github: "rails/rails", branch: "main"
77

88
gem "bootsnap", require: false
99
gem "dotenv-rails"
10+
gem "elasticsearch-model"
11+
gem "elasticsearch-rails"
1012
gem "importmap-rails"
1113
gem "opengraph_parser"
1214
gem "pg"

Gemfile.lock

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,46 @@ GEM
111111
dotenv-rails (2.8.1)
112112
dotenv (= 2.8.1)
113113
railties (>= 3.2)
114+
elasticsearch (7.17.7)
115+
elasticsearch-api (= 7.17.7)
116+
elasticsearch-transport (= 7.17.7)
117+
elasticsearch-api (7.17.7)
118+
multi_json
119+
elasticsearch-model (7.2.1)
120+
activesupport (> 3)
121+
elasticsearch (~> 7)
122+
hashie
123+
elasticsearch-rails (7.2.1)
124+
elasticsearch-transport (7.17.7)
125+
faraday (~> 1)
126+
multi_json
114127
erubi (1.12.0)
128+
faraday (1.10.3)
129+
faraday-em_http (~> 1.0)
130+
faraday-em_synchrony (~> 1.0)
131+
faraday-excon (~> 1.1)
132+
faraday-httpclient (~> 1.0)
133+
faraday-multipart (~> 1.0)
134+
faraday-net_http (~> 1.0)
135+
faraday-net_http_persistent (~> 1.0)
136+
faraday-patron (~> 1.0)
137+
faraday-rack (~> 1.0)
138+
faraday-retry (~> 1.0)
139+
ruby2_keywords (>= 0.0.4)
140+
faraday-em_http (1.0.0)
141+
faraday-em_synchrony (1.0.0)
142+
faraday-excon (1.1.0)
143+
faraday-httpclient (1.0.1)
144+
faraday-multipart (1.0.4)
145+
multipart-post (~> 2)
146+
faraday-net_http (1.0.1)
147+
faraday-net_http_persistent (1.2.0)
148+
faraday-patron (1.0.0)
149+
faraday-rack (1.0.0)
150+
faraday-retry (1.0.3)
115151
globalid (1.1.0)
116152
activesupport (>= 5.0)
153+
hashie (5.0.0)
117154
i18n (1.12.0)
118155
concurrent-ruby (~> 1.0)
119156
importmap-rails (1.1.5)
@@ -134,6 +171,8 @@ GEM
134171
mini_mime (1.1.2)
135172
minitest (5.18.0)
136173
msgpack (1.7.0)
174+
multi_json (1.15.0)
175+
multipart-post (2.3.0)
137176
net-imap (0.3.4)
138177
date
139178
net-protocol
@@ -183,6 +222,7 @@ GEM
183222
connection_pool
184223
reline (0.3.3)
185224
io-console (~> 0.5)
225+
ruby2_keywords (0.0.5)
186226
sidekiq (7.0.7)
187227
concurrent-ruby (< 2)
188228
connection_pool (>= 2.3.0)
@@ -217,6 +257,8 @@ PLATFORMS
217257
DEPENDENCIES
218258
bootsnap
219259
dotenv-rails
260+
elasticsearch-model
261+
elasticsearch-rails
220262
importmap-rails
221263
opengraph_parser
222264
pg

app/models/concerns/searchable.rb

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Description:
2+
# Include this module in models that should be searchable. Also add the model class
3+
# to the Searchable::MODELS array (we're avoiding metaprogramming to keep track of
4+
# included models since it isn't reliable in lazy loading environments).
5+
#
6+
# Models including the concern are expected to implement 'title' and 'searchable_content'
7+
# for indexing. Title will be given higher priority compared to content.
8+
#
9+
# After adding and indexing your models. Search across all models can be performed via
10+
# the Searchable.search method.
11+
12+
module Searchable
13+
extend ActiveSupport::Concern
14+
15+
MODELS = [Link, Post].freeze
16+
17+
def self.search(query)
18+
search_definition = {
19+
query: {
20+
multi_match: {
21+
query: query,
22+
fields: ["title^2", "content"],
23+
},
24+
},
25+
}
26+
27+
Elasticsearch::Model.search(search_definition, MODELS).records
28+
end
29+
30+
def as_indexed_json(_options = {})
31+
{
32+
title: title,
33+
content: searchable_content,
34+
}
35+
end
36+
37+
def should_index?
38+
true
39+
end
40+
41+
def searchable_content
42+
raise NotImplementedError
43+
end
44+
45+
included do
46+
include Elasticsearch::Model
47+
48+
raise "add #{name} to Searchable::MODELS" unless Searchable::MODELS.include?(self)
49+
50+
after_commit on: :create, if: :should_index? do
51+
__elasticsearch__.index_document
52+
end
53+
54+
after_commit on: :update, if: :should_index? do
55+
__elasticsearch__.update_document
56+
end
57+
58+
after_commit on: :destroy do
59+
__elasticsearch__.delete_document
60+
end
61+
62+
settings index: { number_of_shards: 1 } do
63+
mappings dynamic: "false" do
64+
indexes :title, analyzer: "english", boost: 2
65+
indexes :content, analyzer: "english"
66+
end
67+
end
68+
end
69+
end

app/models/link.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
class Link < ApplicationRecord
2+
include Searchable
3+
24
validates_presence_of :url
35
validate :validate_format_of_url
46
validates_inclusion_of :state, in: %w[pending success error]
@@ -8,6 +10,14 @@ class Link < ApplicationRecord
810

911
private
1012

13+
def should_index?
14+
status == "success"
15+
end
16+
17+
def searchable_content
18+
description
19+
end
20+
1121
def enqueue_crawl_job
1222
CrawlLinkJob.perform_later(id)
1323
end

app/models/post.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
class Post < ApplicationRecord
2+
include Searchable
3+
24
validates_presence_of :title
35
validates_presence_of :body
6+
7+
private
8+
9+
def searchable_content
10+
body
11+
end
412
end
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# https://github.com/elastic/elasticsearch-ruby/issues/1429#issuecomment-958162468
2+
module Elasticsearch
3+
class Client
4+
def verify_with_version_or_header(*_args)
5+
@verified = true
6+
end
7+
end
8+
end

0 commit comments

Comments
 (0)