es-elasticity 0.12.0 → 0.13.3.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,158 +0,0 @@
1
- require "elasticity/search"
2
- require "elasticity/multi_search"
3
-
4
- RSpec.describe Elasticity::MultiSearch do
5
- let :client do
6
- double(:client)
7
- end
8
-
9
- let :klass do
10
- Class.new do
11
- include ActiveModel::Model
12
- attr_accessor :_id, :name
13
-
14
- def self.map_hit(hit)
15
- new(_id: hit["_id"], name: hit["_source"]["name"])
16
- end
17
-
18
- def ==(other)
19
- self._id == other._id && self.name == other.name
20
- end
21
- end
22
- end
23
-
24
- let :index_with_one_hit do
25
- {
26
- "hits" => {
27
- "total" => 1,
28
- "hits" => [
29
- { "_id" => 3, "_source" => { "name" => "baz" }}
30
- ]
31
- }
32
- }
33
- end
34
-
35
- let :index_with_two_hits do
36
- {
37
- "hits" => {
38
- "total" => 2,
39
- "hits" => [
40
- { "_id" => 1, "_source" => { "name" => "foo" }},
41
- { "_id" => 2, "_source" => { "name" => "bar" }}
42
- ]
43
- }
44
- }
45
- end
46
-
47
- let :aggregations do
48
- {
49
- "aggregations" => {
50
- "logins_count" => { "value" => 1495 },
51
- "gender" => {
52
- "buckets" => [
53
- {
54
- "doc_count" => 100,
55
- "key" => "M"
56
- },
57
- {
58
- "doc_count" => 100,
59
- "key" => "F"
60
- }
61
- ],
62
- "doc_count_error_upper_bound" => 0,
63
- "sum_other_doc_count" => 0
64
- }
65
- }
66
- }
67
- end
68
-
69
- let :index_with_two_hits_and_aggregations do
70
- index_with_two_hits.merge(aggregations)
71
- end
72
-
73
- let :response do
74
- {
75
- "responses" => [
76
- index_with_two_hits_and_aggregations,
77
- index_with_one_hit
78
- ]
79
- }
80
- end
81
-
82
- it "performs multi search" do
83
- subject.add(:first, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_first", "document_first", { search: :first, size: 2 })), documents: klass)
84
- subject.add(:second, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_second", "document_second", { search: :second })), documents: klass)
85
-
86
- expect(Elasticity.config.client).to receive(:msearch).with(body: [
87
- { index: "index_first", type: "document_first", search: { search: :first, size: 2 } },
88
- { index: "index_second", type: "document_second", search: { search: :second } },
89
- ]).and_return(response)
90
-
91
- expect(Array(subject[:first])).to eq [klass.new(_id: 1, name: "foo"), klass.new(_id: 2, name: "bar")]
92
- expect(Array(subject[:second])).to eq [klass.new(_id: 3, name: "baz")]
93
- expect(subject[:first].total).to eq 2
94
- expect(subject[:first].total_pages).to eq 1
95
- expect(subject[:first].current_page).to eq 1
96
- expect(subject[:first].aggregations).to eq aggregations["aggregations"]
97
- expect(subject[:second].aggregations).to eq Hash.new
98
- expect(subject[:third]).to be_nil
99
- end
100
-
101
- it "performs multi search with additional arguments" do
102
- subject = Elasticity::MultiSearch.new(search_type: :dfs_query_then_fetch)
103
- subject.add(:first, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_first", "document_first", { search: :first, size: 2 })), documents: klass)
104
- subject.add(:second, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_second", "document_second", { search: :second })), documents: klass)
105
-
106
- expect(Elasticity.config.client).to receive(:msearch).with(search_type: :dfs_query_then_fetch, body: [
107
- { index: "index_first", type: "document_first", search: { search: :first, size: 2 } },
108
- { index: "index_second", type: "document_second", search: { search: :second } },
109
- ]).and_return(response)
110
-
111
- expect(Array(subject[:first])).to eq([klass.new(_id: 1, name: "foo"), klass.new(_id: 2, name: "bar")])
112
- end
113
-
114
- context "when there was an error for one query" do
115
- let(:error) do
116
- {
117
- "error" => {
118
- "root_cause" => [
119
- {
120
- "type" => "too_many_clauses",
121
- "reason" => "too_many_clauses: maxClauseCount is set to 1024"
122
- }
123
- ],
124
- "type" => "search_phase_execution_exception",
125
- "grouped" => true,
126
- },
127
- "status" => 400
128
- }
129
- end
130
-
131
- let(:response) do
132
- {
133
- "responses" => [
134
- index_with_two_hits_and_aggregations,
135
- index_with_one_hit,
136
- error
137
- ]
138
- }
139
- end
140
-
141
- before do
142
- expect(Elasticity.config.client).to receive(:msearch).with(body: [
143
- { index: "index_first", type: "document_first", search: { search: :first, size: 2 } },
144
- { index: "index_second", type: "document_second", search: { search: :second } },
145
- { index: "index_third", type: "document_third", search: { search: :third } },
146
- ]).and_return(response)
147
- end
148
-
149
- it "raises an error while trying to access the query result" do
150
- subject.add(:first, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_first", "document_first", { search: :first, size: 2 })), documents: klass)
151
- subject.add(:second, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_second", "document_second", { search: :second })), documents: klass)
152
- subject.add(:third, Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new("index_third", "document_third", { search: :third })), documents: klass)
153
-
154
- expect(Array(subject[:first])).to eq [klass.new(_id: 1, name: "foo"), klass.new(_id: 2, name: "bar")]
155
- expect { subject[:third] }.to raise_error Elasticsearch::Transport::Transport::Errors::BadRequest, error.to_json
156
- end
157
- end
158
- end
@@ -1,230 +0,0 @@
1
- require "elasticity/search"
2
-
3
- RSpec.describe "Search" do
4
- let(:client) { double(:client) }
5
- let(:index_name) { "index_name" }
6
- let(:document_type) { "document" }
7
- let(:body) { {} }
8
-
9
- let :full_response do
10
- { "hits" => { "total" => 2, "hits" => [
11
- { "_id" => 1, "_source" => { "name" => "foo" } },
12
- { "_id" => 2, "_source" => { "name" => "bar" } },
13
- ]}}
14
- end
15
-
16
- let :aggregations do
17
- {
18
- "logins_count" => { "value" => 1495 },
19
- "gender" => {
20
- "buckets" => [
21
- {
22
- "doc_count" => 100,
23
- "key" => "M"
24
- },
25
- {
26
- "doc_count" => 100,
27
- "key" => "F"
28
- }
29
- ],
30
- "doc_count_error_upper_bound" => 0,
31
- "sum_other_doc_count" => 0
32
- }
33
- }
34
- end
35
-
36
- let :full_response_with_aggregations do
37
- full_response.merge("aggregations" => aggregations)
38
- end
39
-
40
- let :ids_response do
41
- { "hits" => { "total" => 2, "hits" => [
42
- { "_id" => 1 },
43
- { "_id" => 2 },
44
- ]}}
45
- end
46
-
47
- let :empty_response do
48
- { "hits" => { "total" => 0, "hits" => [] }}
49
- end
50
-
51
- let :scan_response do
52
- { "_scroll_id" => "abc123", "hits" => { "total" => 2, "hits" => [
53
- { "_id" => 1, "_source" => { "name" => "foo" } }
54
- ]}}
55
- end
56
-
57
- let :scroll_response do
58
- { "_scroll_id" => "abc456", "hits" => { "total" => 1, "hits" => [
59
- { "_id" => 2, "_source" => { "name" => "bar" } },
60
- ]}}
61
- end
62
-
63
- let :mapper do
64
- -> (hit) {
65
- klass.new(_id: hit["_id"], name: hit["_source"]["name"], age: hit["_source"]["age"])
66
- }
67
- end
68
-
69
- let :klass do
70
- Class.new do
71
- include ActiveModel::Model
72
- attr_accessor :_id, :name, :age
73
-
74
- def ==(other)
75
- self._id == other._id && self.name == other.name
76
- end
77
- end
78
- end
79
-
80
- describe Elasticity::Search::Facade do
81
- subject do
82
- described_class.new(client, Elasticity::Search::Definition.new(index_name, document_type, body))
83
- end
84
-
85
- it "searches the index and return document models" do
86
- expect(client).to receive(:search).with(index: index_name, type: document_type, body: body).and_return(full_response)
87
-
88
- docs = subject.documents(mapper)
89
- expected = [klass.new(_id: 1, name: "foo"), klass.new(_id: 2, name: "bar")]
90
-
91
- expect(docs.total).to eq 2
92
- expect(docs.size).to eq expected.size
93
-
94
- expect(docs).to_not be_empty
95
- expect(docs).to_not be_blank
96
-
97
- expect(docs[0].name).to eq expected[0].name
98
- expect(docs[1].name).to eq expected[1].name
99
-
100
- expect(docs.each.first).to eq expected[0]
101
- expect(Array(docs)).to eq expected
102
- end
103
-
104
- it "searches and the index returns aggregations" do
105
- expect(client).to receive(:search).with(index: index_name, type: document_type, body: body).and_return(full_response_with_aggregations)
106
-
107
- docs = subject.documents(mapper)
108
- expect(docs.aggregations).to eq aggregations
109
- end
110
-
111
- it "searches using scan&scroll" do
112
- expect(client).to receive(:search).with(index: index_name, type: document_type, body: body, search_type: :query_then_fetch, size: 100, scroll: "1m").and_return(scan_response)
113
- expect(client).to receive(:scroll).with(scroll_id: "abc123", scroll: "1m", body: { scroll_id: "abc123" }).and_return(scroll_response)
114
- expect(client).to receive(:scroll).with(scroll_id: "abc456", scroll: "1m", body: { scroll_id: "abc456" }).and_return(empty_response)
115
-
116
- docs = subject.scan_documents(mapper)
117
- expected = [klass.new(_id: 1, name: "foo"), klass.new(_id: 2, name: "bar")]
118
-
119
- expect(docs.total).to eq 2
120
-
121
- expect(docs).to_not be_empty
122
- expect(docs).to_not be_blank
123
-
124
- expect(Array(docs)).to eq expected
125
- end
126
-
127
- it "searches the index and return active record models" do
128
- expect(client).to receive(:search).with(index: index_name, type: document_type, body: body.merge(_source: false)).and_return(ids_response)
129
-
130
- relation = double(:relation,
131
- connection: double(:connection),
132
- table_name: "table_name",
133
- klass: double(:klass, primary_key: "id"),
134
- to_sql: "SELECT * FROM table_name WHERE id IN (1)"
135
- )
136
-
137
- allow(relation.connection).to receive(:quote_column_name) { |name| name }
138
- allow(relation.connection).to receive(:quote) { |name| name }
139
-
140
- expect(relation).to receive(:where).with("table_name.id IN (?)", [1, 2]).and_return(relation)
141
- expect(relation).to receive(:order).with("FIELD(table_name.id, 1,2)").and_return(relation)
142
-
143
- expect(subject.active_records(relation).to_sql).to eq "SELECT * FROM table_name WHERE id IN (1)"
144
- end
145
- end
146
-
147
- describe Elasticity::Search::LazySearch do
148
- it "provides defaul properties for pagination" do
149
- subject = Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new(index_name, document_type, body))
150
- expect(client).to receive(:search).with(index: index_name, type: document_type, body: body).and_return(full_response)
151
- docs = subject.documents(mapper)
152
-
153
- expect(docs.per_page).to eq(10)
154
- expect(docs.total_pages).to eq(1)
155
- expect(docs.current_page).to eq(1)
156
- expect(docs.next_page).to eq(nil)
157
- expect(docs.previous_page).to eq(nil)
158
- end
159
-
160
- it "provides custom properties for pagination" do
161
- subject = Elasticity::Search::Facade.new(
162
- client,
163
- Elasticity::Search::Definition.new(
164
- index_name,
165
- document_type,
166
- { size: 15, from: 15, filter: {} }
167
- )
168
- )
169
- expect(client).to receive(:search).
170
- with(
171
- index: index_name,
172
- type: document_type,
173
- body: { size: 15, from: 15, filter: {} }
174
- ).and_return({ "hits" => { "total" => 112, "hits" => [] } })
175
- docs = subject.documents(mapper)
176
-
177
- expect(docs.per_page).to eq(15)
178
- expect(docs.total_pages).to eq(8)
179
- expect(docs.current_page).to eq(2)
180
- expect(docs.next_page).to eq(3)
181
- expect(docs.previous_page).to eq(1)
182
- end
183
-
184
- it "merges in additional arguments for search" do
185
- results = double(:results, :[] => { "hits" => [] })
186
- subject = Elasticity::Search::Facade.new(
187
- client,
188
- Elasticity::Search::Definition.new(index_name, document_type, {})
189
- )
190
-
191
- expect(client).to receive(:search).with(
192
- index: index_name,
193
- type: document_type,
194
- body: {},
195
- search_type: :dfs_query_and_fetch
196
- ).and_return(results)
197
- subject.documents(mapper, search_type: :dfs_query_and_fetch).search_results
198
- end
199
- end
200
-
201
- describe Elasticity::Search::DocumentProxy do
202
- let :search do
203
- Elasticity::Search::Facade.new(client, Elasticity::Search::Definition.new(index_name, "document", body))
204
- end
205
-
206
- subject do
207
- described_class.new(search, mapper)
208
- end
209
-
210
- it "automatically maps the documents into the provided Document class" do
211
- expect(client).to receive(:search).with(index: index_name, type: document_type, body: body).and_return(full_response)
212
- expect(Array(subject)).to eq [klass.new(_id: 1, name: "foo"), klass.new(_id: 2, name: "bar")]
213
- end
214
-
215
- it "delegates active_records for the underlying search" do
216
- records = double(:records)
217
- rel = double(:relation)
218
- expect(search).to receive(:active_records).with(rel).and_return(records)
219
- expect(subject.active_records(rel)).to be records
220
- end
221
-
222
- it "accepts additional arguments for a search" do
223
- results = double(:results)
224
-
225
- expect(search).to receive(:documents).with(mapper, search_type: :dfs_query_then_fetch).and_return(results)
226
- expect(subject.documents(search_type: :dfs_query_then_fetch)).to eq(results)
227
- end
228
-
229
- end
230
- end
@@ -1,85 +0,0 @@
1
- RSpec.describe Elasticity::Strategies::SingleIndex, elasticsearch: true do
2
- subject do
3
- described_class.new(Elasticity.config.client, "test_index_name", "document")
4
- end
5
-
6
- let :index_def do
7
- {
8
- "mappings" => {
9
- "document" => {
10
- "properties" => {
11
- "name" => { "type" => "text" }
12
- }
13
- }
14
- }
15
- }
16
- end
17
-
18
- after do
19
- subject.delete_if_defined
20
- end
21
-
22
- it "allows creating, recreating and deleting an index" do
23
- subject.create(index_def)
24
- expect(subject.mapping).to eq(index_def)
25
-
26
- subject.recreate(index_def)
27
- expect(subject.mapping).to eq(index_def)
28
-
29
- subject.delete
30
- expect(subject.mapping).to be nil
31
- end
32
-
33
- it "returns nil for mapping and settings when index does not exist" do
34
- expect(subject.mapping).to be nil
35
- expect(subject.settings).to be nil
36
- end
37
-
38
- context "with existing index" do
39
- before do
40
- subject.create_if_undefined(index_def)
41
- end
42
-
43
- it "allows adding, getting and removing documents from the index" do
44
- subject.index_document("document", 1, name: "test")
45
-
46
- doc = subject.get_document("document", 1)
47
- expect(doc["_source"]["name"]).to eq("test")
48
-
49
- subject.delete_document("document", 1)
50
- expect { subject.get_document("document", 1) }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
51
- end
52
-
53
- it "allows batching index and delete actions" do
54
- results_a = subject.bulk do |b|
55
- b.index "document", 1, name: "foo"
56
- end
57
- expect(results_a["errors"]).to be_falsey
58
-
59
- results_b = subject.bulk do |b|
60
- b.index "document", 2, name: "bar"
61
- b.delete "document", 1
62
- end
63
-
64
- expect(results_b["errors"]).to be_falsey
65
-
66
- subject.flush
67
-
68
- expect { subject.get_document("document", 1) }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
69
- expect(subject.get_document("document", 2)).to eq({"_index"=>"test_index_name", "_type"=>"document", "_id"=>"2", "_version"=>1, "found"=>true, "_source"=>{"name"=>"bar"}})
70
- end
71
-
72
- it "allows deleting by query" do
73
- subject.index_document("document", 1, name: "foo")
74
- subject.index_document("document", 2, name: "bar")
75
-
76
- subject.flush
77
- subject.delete_by_query("document", query: { term: { name: "foo" } })
78
-
79
- expect { subject.get_document("document", 1) }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
80
- expect { subject.get_document("document", 2) }.to_not raise_error
81
-
82
- subject.flush
83
- end
84
- end
85
- end