es-elasticity 0.12.0 → 0.13.3.pre1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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