elastic-app-search 7.4.0 → 7.4.1
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.
- checksums.yaml +4 -4
- data/README.md +287 -20
- data/lib/elastic/app-search/client.rb +16 -2
- data/lib/elastic/app-search/client/analytics.rb +25 -0
- data/lib/elastic/app-search/client/click.rb +15 -0
- data/lib/elastic/app-search/client/credentials.rb +35 -0
- data/lib/elastic/app-search/client/curations.rb +35 -0
- data/lib/elastic/app-search/client/engines.rb +2 -0
- data/lib/elastic/app-search/client/logs.rb +15 -0
- data/lib/elastic/app-search/client/schema.rb +20 -0
- data/lib/elastic/app-search/client/synonyms.rb +35 -0
- data/lib/elastic/app-search/version.rb +1 -1
- data/spec/analytics_spec.rb +82 -0
- data/spec/click_spec.rb +30 -0
- data/spec/client_spec.rb +8 -452
- data/spec/config_helper.rb +4 -0
- data/spec/credentials_spec.rb +75 -0
- data/spec/curations_spec.rb +82 -0
- data/spec/documents_spec.rb +159 -0
- data/spec/engines_spec.rb +74 -0
- data/spec/logs_spec.rb +33 -0
- data/spec/query_suggestion_spec.rb +37 -0
- data/spec/schema_spec.rb +23 -0
- data/spec/search_settings_spec.rb +65 -0
- data/spec/search_spec.rb +96 -0
- data/spec/spec_helper.rb +69 -0
- data/spec/synonyms_spec.rb +65 -0
- metadata +33 -2
@@ -0,0 +1,35 @@
|
|
1
|
+
# Credentials API - https://swiftype.com/documentation/app-search/api/credentials
|
2
|
+
module Elastic
|
3
|
+
module AppSearch
|
4
|
+
class Client
|
5
|
+
module Credentials
|
6
|
+
|
7
|
+
# Retrieve available credentials
|
8
|
+
def list_credentials(current: 1, size: 20)
|
9
|
+
get("credentials", :page => { :current => current, :size => size })
|
10
|
+
end
|
11
|
+
|
12
|
+
# Retrieve a credential
|
13
|
+
def get_credential(name)
|
14
|
+
get("credentials/#{name}")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new credential
|
18
|
+
def create_credential(options)
|
19
|
+
post("credentials", options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Update an existing credential
|
23
|
+
def update_credential(name, options)
|
24
|
+
put("credentials/#{name}", options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Destroy an existing credential
|
28
|
+
def destroy_credential(name)
|
29
|
+
delete("credentials/#{name}")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Curations API - https://swiftype.com/documentation/app-search/api/curations
|
2
|
+
module Elastic
|
3
|
+
module AppSearch
|
4
|
+
class Client
|
5
|
+
module Curations
|
6
|
+
|
7
|
+
# Retrieve available curations for the engine.
|
8
|
+
def list_curations(engine_name, current: 1, size: 20)
|
9
|
+
get("engines/#{engine_name}/curations", :page => { :current => current, :size => size })
|
10
|
+
end
|
11
|
+
|
12
|
+
# Create a new curation.
|
13
|
+
def create_curation(engine_name, options)
|
14
|
+
post("engines/#{engine_name}/curations", options)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Retrieve a curation by id.
|
18
|
+
def get_curation(engine_name, id)
|
19
|
+
get("engines/#{engine_name}/curations/#{id}")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Update an existing curation.
|
23
|
+
def update_curation(engine_name, id, options)
|
24
|
+
put("engines/#{engine_name}/curations/#{id}", options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Delete a curation by id.
|
28
|
+
def destroy_curation(engine_name, id)
|
29
|
+
delete("engines/#{engine_name}/curations/#{id}")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -4,6 +4,7 @@ module Elastic
|
|
4
4
|
module AppSearch
|
5
5
|
class Client
|
6
6
|
module Engines
|
7
|
+
|
7
8
|
def list_engines(current: 1, size: 20)
|
8
9
|
get("engines", :page => { :current => current, :size => size })
|
9
10
|
end
|
@@ -21,6 +22,7 @@ module Elastic
|
|
21
22
|
def destroy_engine(engine_name)
|
22
23
|
delete("engines/#{engine_name}")
|
23
24
|
end
|
25
|
+
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Logs API - https://swiftype.com/documentation/app-search/api/logs
|
2
|
+
module Elastic
|
3
|
+
module AppSearch
|
4
|
+
class Client
|
5
|
+
module Logs
|
6
|
+
|
7
|
+
# The API Log displays API request and response data at the Engine level.
|
8
|
+
def get_api_logs(engine_name, options)
|
9
|
+
post("engines/#{engine_name}/logs/api", options)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Schema API - https://swiftype.com/documentation/app-search/api/schema
|
2
|
+
module Elastic
|
3
|
+
module AppSearch
|
4
|
+
class Client
|
5
|
+
module Schema
|
6
|
+
|
7
|
+
# Retrieve schema for the current engine.
|
8
|
+
def get_schema(engine_name)
|
9
|
+
get("engines/#{engine_name}/schema")
|
10
|
+
end
|
11
|
+
|
12
|
+
# Create a new schema field or update existing schema for the current engine.
|
13
|
+
def update_schema(engine_name, schema)
|
14
|
+
post("engines/#{engine_name}/schema", schema)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Synonyms API - https://swiftype.com/documentation/app-search/api/synonyms
|
2
|
+
module Elastic
|
3
|
+
module AppSearch
|
4
|
+
class Client
|
5
|
+
module Synonyms
|
6
|
+
|
7
|
+
# Retrieve available synonym sets for the engine.
|
8
|
+
def list_synonym_sets(engine_name, current: 1, size: 20)
|
9
|
+
get("engines/#{engine_name}/synonyms", :page => { :current => current, :size => size })
|
10
|
+
end
|
11
|
+
|
12
|
+
# Retrieve a synonym set by id
|
13
|
+
def get_synonym_set(engine_name, id)
|
14
|
+
get("engines/#{engine_name}/synonyms/#{id}")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create a new synonym set
|
18
|
+
def create_synonym_set(engine_name, body)
|
19
|
+
post("engines/#{engine_name}/synonyms", body)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Update an existing synonym set
|
23
|
+
def update_synonym_set(engine_name, id, body)
|
24
|
+
put("engines/#{engine_name}/synonyms/#{id}", body)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Delete a synonym set by id
|
28
|
+
def destroy_synonym_set(engine_name, id)
|
29
|
+
delete("engines/#{engine_name}/synonyms/#{id}")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
describe Elastic::AppSearch::Client::Analytics do
|
2
|
+
include_context 'App Search Credentials'
|
3
|
+
include_context 'Test Engine'
|
4
|
+
|
5
|
+
let(:client) { Elastic::AppSearch::Client.new(client_options) }
|
6
|
+
|
7
|
+
context '#get_top_clicks_analytics' do
|
8
|
+
subject do
|
9
|
+
client.get_top_clicks_analytics(
|
10
|
+
engine_name,
|
11
|
+
:query => 'cats',
|
12
|
+
:page => {
|
13
|
+
:size => 20,
|
14
|
+
},
|
15
|
+
:filters => {
|
16
|
+
:date => {
|
17
|
+
:from => Time.now.iso8601,
|
18
|
+
:to => Time.now.iso8601
|
19
|
+
}
|
20
|
+
}
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'will query for analytics' do
|
25
|
+
expect(subject['results']).to(eq([]))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#get_top_queries_analytics' do
|
30
|
+
subject do
|
31
|
+
client.get_top_queries_analytics(
|
32
|
+
engine_name,
|
33
|
+
:page => {
|
34
|
+
:size => 20
|
35
|
+
},
|
36
|
+
:filters => {
|
37
|
+
:date => {
|
38
|
+
:from => Time.now.iso8601,
|
39
|
+
:to => Time.now.iso8601
|
40
|
+
}
|
41
|
+
}
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'will query for analytics' do
|
46
|
+
expect(subject['results']).to(eq([]))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context '#get_count_analytics' do
|
51
|
+
let(:from) { Time.now.iso8601 }
|
52
|
+
let(:to) { Time.now.iso8601 }
|
53
|
+
|
54
|
+
subject do
|
55
|
+
client.get_count_analytics(
|
56
|
+
engine_name,
|
57
|
+
:filters => {
|
58
|
+
:all => [
|
59
|
+
{
|
60
|
+
:tag => ['mobile', 'web']
|
61
|
+
}, {
|
62
|
+
:query => 'cats'
|
63
|
+
}, {
|
64
|
+
:document_id => '163'
|
65
|
+
}, {
|
66
|
+
:date => {
|
67
|
+
:from => from,
|
68
|
+
:to => to
|
69
|
+
}
|
70
|
+
}
|
71
|
+
]
|
72
|
+
},
|
73
|
+
:interval => 'hour'
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'will query for analytics' do
|
78
|
+
expect(subject['results'][0]['clicks']).to(eq(0))
|
79
|
+
expect(subject['results'][0]['queries']).to(eq(0))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/spec/click_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
describe Elastic::AppSearch::Client::Click do
|
2
|
+
include_context 'App Search Credentials'
|
3
|
+
include_context 'Test Engine'
|
4
|
+
|
5
|
+
let(:client) { Elastic::AppSearch::Client.new(client_options) }
|
6
|
+
|
7
|
+
context '#log_click_through' do
|
8
|
+
let(:documents) { [first_document, second_document] }
|
9
|
+
let(:first_document_id) { 'id' }
|
10
|
+
let(:first_document) { { 'id' => first_document_id } }
|
11
|
+
let(:second_document_id) { 'another_id' }
|
12
|
+
let(:second_document) { { 'id' => second_document_id } }
|
13
|
+
|
14
|
+
before { client.index_documents(engine_name, documents) }
|
15
|
+
|
16
|
+
subject do
|
17
|
+
client.log_click_through(
|
18
|
+
engine_name,
|
19
|
+
:query => 'cat videos',
|
20
|
+
:document_id => first_document_id,
|
21
|
+
:request_id => 'e4c4dea0bd7ad3d2f676575ef16dc7d2',
|
22
|
+
:tags => ['firefox', 'web browser']
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'will log a click' do
|
27
|
+
expect(subject[0]['id']).not_to(be_empty)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/client_spec.rb
CHANGED
@@ -2,42 +2,9 @@ require 'config_helper'
|
|
2
2
|
require 'securerandom'
|
3
3
|
|
4
4
|
describe Elastic::AppSearch::Client do
|
5
|
-
let(:engine_name) { "ruby-client-test-#{SecureRandom.hex}" }
|
6
|
-
|
7
5
|
include_context 'App Search Credentials'
|
8
6
|
let(:client) { Elastic::AppSearch::Client.new(client_options) }
|
9
7
|
|
10
|
-
before(:all) do
|
11
|
-
# Bootstraps a static engine for 'read-only' options that require indexing
|
12
|
-
# across the test suite
|
13
|
-
@static_engine_name = "ruby-client-test-static-#{SecureRandom.hex}"
|
14
|
-
as_api_key = ConfigHelper.get_as_api_key
|
15
|
-
as_host_identifier = ConfigHelper.get_as_host_identifier
|
16
|
-
as_api_endpoint = ConfigHelper.get_as_api_endpoint
|
17
|
-
client_options = ConfigHelper.get_client_options(as_api_key, as_host_identifier, as_api_endpoint)
|
18
|
-
@static_client = Elastic::AppSearch::Client.new(client_options)
|
19
|
-
@static_client.create_engine(@static_engine_name)
|
20
|
-
|
21
|
-
@document1 = { 'id' => '1', 'title' => 'The Great Gatsby' }
|
22
|
-
@document2 = { 'id' => '2', 'title' => 'Catcher in the Rye' }
|
23
|
-
@documents = [@document1, @document2]
|
24
|
-
@static_client.index_documents(@static_engine_name, @documents)
|
25
|
-
|
26
|
-
# Wait until documents are indexed
|
27
|
-
start = Time.now
|
28
|
-
ready = false
|
29
|
-
until (ready)
|
30
|
-
sleep(3)
|
31
|
-
results = @static_client.search(@static_engine_name, '')
|
32
|
-
ready = true if results['results'].length == 2
|
33
|
-
ready = true if (Time.now - start).to_i >= 120 # Time out after 2 minutes
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
after(:all) do
|
38
|
-
@static_client.destroy_engine(@static_engine_name)
|
39
|
-
end
|
40
|
-
|
41
8
|
describe '#create_signed_search_key' do
|
42
9
|
let(:key) { 'private-xxxxxxxxxxxxxxxxxxxx' }
|
43
10
|
let(:api_key_name) { 'private-key' }
|
@@ -52,9 +19,9 @@ describe Elastic::AppSearch::Client do
|
|
52
19
|
end
|
53
20
|
|
54
21
|
it 'should build a valid jwt' do
|
55
|
-
decoded_token = JWT.decode
|
56
|
-
expect(decoded_token[0]['api_key_name']).to
|
57
|
-
expect(decoded_token[0]['query']).to
|
22
|
+
decoded_token = JWT.decode(subject, key, true, :algorithm => 'HS256')
|
23
|
+
expect(decoded_token[0]['api_key_name']).to(eq(api_key_name))
|
24
|
+
expect(decoded_token[0]['query']).to(eq('cat'))
|
58
25
|
end
|
59
26
|
end
|
60
27
|
|
@@ -62,426 +29,15 @@ describe Elastic::AppSearch::Client do
|
|
62
29
|
it 'should include client name and version in headers' do
|
63
30
|
stub_request(:any, "#{client_options[:host_identifier]}.api.swiftype.com/api/as/v1/engines")
|
64
31
|
client.list_engines
|
65
|
-
expect(WebMock).to
|
32
|
+
expect(WebMock).to(
|
33
|
+
have_requested(:get, "https://#{client_options[:host_identifier]}.api.swiftype.com/api/as/v1/engines")
|
66
34
|
.with(
|
67
35
|
:headers => {
|
68
36
|
'X-Swiftype-Client' => 'elastic-app-search-ruby',
|
69
37
|
'X-Swiftype-Client-Version' => Elastic::AppSearch::VERSION
|
70
38
|
}
|
71
39
|
)
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
context 'Documents' do
|
76
|
-
let(:document) { { 'url' => 'http://www.youtube.com/watch?v=v1uyQZNg2vE' } }
|
77
|
-
|
78
|
-
before do
|
79
|
-
client.create_engine(engine_name) rescue Elastic::AppSearch::BadRequest
|
80
|
-
end
|
81
|
-
|
82
|
-
after do
|
83
|
-
client.destroy_engine(engine_name) rescue Elastic::AppSearch::NonExistentRecord
|
84
|
-
end
|
85
|
-
|
86
|
-
describe '#index_document' do
|
87
|
-
subject { client.index_document(engine_name, document) }
|
88
|
-
|
89
|
-
it 'should return a processed document status hash' do
|
90
|
-
expect(subject).to match('id' => anything)
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'when the document has an id' do
|
94
|
-
let(:id) { 'some_id' }
|
95
|
-
let(:document) { { 'id' => id, 'url' => 'http://www.youtube.com/watch?v=v1uyQZNg2vE' } }
|
96
|
-
|
97
|
-
it 'should return a processed document status hash with the same id' do
|
98
|
-
expect(subject).to eq('id' => id)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context 'when a document has processing errors' do
|
103
|
-
let(:document) { { 'id' => 'too long' * 100 } }
|
104
|
-
|
105
|
-
it 'should raise an error when the API returns errors in the response' do
|
106
|
-
expect do
|
107
|
-
subject
|
108
|
-
end.to raise_error(Elastic::AppSearch::InvalidDocument, /Invalid field/)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
context 'when a document has a Ruby Time object' do
|
113
|
-
let(:time_rfc3339) { '2018-01-01T01:01:01+00:00' }
|
114
|
-
let(:time_object) { Time.parse(time_rfc3339) }
|
115
|
-
let(:document) { { 'created_at' => time_object } }
|
116
|
-
|
117
|
-
it 'should serialize the time object in RFC 3339' do
|
118
|
-
response = subject
|
119
|
-
expect(response).to have_key('id')
|
120
|
-
document_id = response.fetch('id')
|
121
|
-
expect do
|
122
|
-
documents = client.get_documents(engine_name, [document_id])
|
123
|
-
expect(documents.size).to eq(1)
|
124
|
-
expect(documents.first['created_at']).to eq(time_rfc3339)
|
125
|
-
end.to_not raise_error
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
describe '#index_documents' do
|
131
|
-
let(:documents) { [document, second_document] }
|
132
|
-
let(:second_document_id) { 'another_id' }
|
133
|
-
let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
|
134
|
-
subject { client.index_documents(engine_name, documents) }
|
135
|
-
|
136
|
-
it 'should return an array of document status hashes' do
|
137
|
-
expect(subject).to match(
|
138
|
-
[
|
139
|
-
{ 'id' => anything, 'errors' => [] },
|
140
|
-
{ 'id' => second_document_id, 'errors' => [] }
|
141
|
-
]
|
142
|
-
)
|
143
|
-
end
|
144
|
-
|
145
|
-
context 'when one of the documents has processing errors' do
|
146
|
-
let(:second_document) { { 'id' => 'too long' * 100 } }
|
147
|
-
|
148
|
-
it 'should return respective errors in an array of document processing hashes' do
|
149
|
-
expect(subject).to match(
|
150
|
-
[
|
151
|
-
{ 'id' => anything, 'errors' => [] },
|
152
|
-
{ 'id' => anything, 'errors' => ['Invalid field type: id must be less than 800 characters'] },
|
153
|
-
]
|
154
|
-
)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
describe '#update_documents' do
|
160
|
-
let(:documents) { [document, second_document] }
|
161
|
-
let(:second_document_id) { 'another_id' }
|
162
|
-
let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
|
163
|
-
let(:updates) do
|
164
|
-
[
|
165
|
-
{
|
166
|
-
'id' => second_document_id,
|
167
|
-
'url' => 'https://www.example.com'
|
168
|
-
}
|
169
|
-
]
|
170
|
-
end
|
171
|
-
|
172
|
-
subject { client.update_documents(engine_name, updates) }
|
173
|
-
|
174
|
-
before do
|
175
|
-
client.index_documents(engine_name, documents)
|
176
|
-
end
|
177
|
-
|
178
|
-
# Note that since indexing a document takes up to a minute,
|
179
|
-
# we don't expect this to succeed, so we simply verify that
|
180
|
-
# the request responded with the correct 'id', even though
|
181
|
-
# the 'errors' object likely contains errors.
|
182
|
-
it 'should update existing documents' do
|
183
|
-
expect(subject).to match(['id' => second_document_id, 'errors' => anything])
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe '#get_documents' do
|
188
|
-
let(:documents) { [first_document, second_document] }
|
189
|
-
let(:first_document_id) { 'id' }
|
190
|
-
let(:first_document) { { 'id' => first_document_id, 'url' => 'https://www.youtube.com/watch?v=v1uyQZNg2vE' } }
|
191
|
-
let(:second_document_id) { 'another_id' }
|
192
|
-
let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
|
193
|
-
|
194
|
-
subject { client.get_documents(engine_name, [first_document_id, second_document_id]) }
|
195
|
-
|
196
|
-
before do
|
197
|
-
client.index_documents(engine_name, documents)
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'will return documents by id' do
|
201
|
-
response = subject
|
202
|
-
expect(response.size).to eq(2)
|
203
|
-
expect(response[0]['id']).to eq(first_document_id)
|
204
|
-
expect(response[1]['id']).to eq(second_document_id)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
describe '#list_documents' do
|
209
|
-
let(:documents) { [first_document, second_document] }
|
210
|
-
let(:first_document_id) { 'id' }
|
211
|
-
let(:first_document) { { 'id' => first_document_id, 'url' => 'https://www.youtube.com/watch?v=v1uyQZNg2vE' } }
|
212
|
-
let(:second_document_id) { 'another_id' }
|
213
|
-
let(:second_document) { { 'id' => second_document_id, 'url' => 'https://www.youtube.com/watch?v=9T1vfsHYiKY' } }
|
214
|
-
|
215
|
-
before do
|
216
|
-
client.index_documents(engine_name, documents)
|
217
|
-
end
|
218
|
-
|
219
|
-
context 'when no options are specified' do
|
220
|
-
it 'will return all documents' do
|
221
|
-
response = client.list_documents(engine_name)
|
222
|
-
expect(response['results'].size).to eq(2)
|
223
|
-
expect(response['results'][0]['id']).to eq(first_document_id)
|
224
|
-
expect(response['results'][1]['id']).to eq(second_document_id)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
context 'when options are specified' do
|
229
|
-
it 'will return all documents' do
|
230
|
-
response = client.list_documents(engine_name, :page => { :size => 1, :current => 2 })
|
231
|
-
expect(response['results'].size).to eq(1)
|
232
|
-
expect(response['results'][0]['id']).to eq(second_document_id)
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
context 'Search' do
|
239
|
-
describe '#search' do
|
240
|
-
subject { @static_client.search(@static_engine_name, query, options) }
|
241
|
-
let(:query) { '' }
|
242
|
-
let(:options) { { 'page' => { 'size' => 2 } } }
|
243
|
-
|
244
|
-
it 'should execute a search query' do
|
245
|
-
expect(subject).to match(
|
246
|
-
'meta' => anything,
|
247
|
-
'results' => [anything, anything]
|
248
|
-
)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
describe '#multi_search' do
|
253
|
-
subject { @static_client.multi_search(@static_engine_name, queries) }
|
254
|
-
|
255
|
-
context 'when options are provided' do
|
256
|
-
let(:queries) do
|
257
|
-
[
|
258
|
-
{ 'query' => 'gatsby', 'options' => { 'page' => { 'size' => 1 } } },
|
259
|
-
{ 'query' => 'catcher', 'options' => { 'page' => { 'size' => 1 } } }
|
260
|
-
]
|
261
|
-
end
|
262
|
-
|
263
|
-
it 'should execute a multi search query' do
|
264
|
-
response = subject
|
265
|
-
expect(response).to match(
|
266
|
-
[
|
267
|
-
{
|
268
|
-
'meta' => anything,
|
269
|
-
'results' => [{ 'id' => { 'raw' => '1' }, 'title' => anything, '_meta' => anything }]
|
270
|
-
},
|
271
|
-
{
|
272
|
-
'meta' => anything,
|
273
|
-
'results' => [{ 'id' => { 'raw' => '2' }, 'title' => anything, '_meta' => anything }]
|
274
|
-
}
|
275
|
-
]
|
276
|
-
)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
context 'when options are omitted' do
|
281
|
-
let(:queries) do
|
282
|
-
[
|
283
|
-
{ 'query' => 'gatsby' },
|
284
|
-
{ 'query' => 'catcher' }
|
285
|
-
]
|
286
|
-
end
|
287
|
-
|
288
|
-
it 'should execute a multi search query' do
|
289
|
-
response = subject
|
290
|
-
expect(response).to match(
|
291
|
-
[
|
292
|
-
{
|
293
|
-
'meta' => anything,
|
294
|
-
'results' => [{ 'id' => { 'raw' => '1' }, 'title' => anything, '_meta' => anything }]
|
295
|
-
},
|
296
|
-
{
|
297
|
-
'meta' => anything,
|
298
|
-
'results' => [{ 'id' => { 'raw' => '2' }, 'title' => anything, '_meta' => anything }]
|
299
|
-
}
|
300
|
-
]
|
301
|
-
)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
context 'when a search is bad' do
|
306
|
-
let(:queries) do
|
307
|
-
[
|
308
|
-
{
|
309
|
-
'query' => 'cat',
|
310
|
-
'options' => { 'search_fields' => { 'taco' => {} } }
|
311
|
-
}, {
|
312
|
-
'query' => 'dog',
|
313
|
-
'options' => { 'search_fields' => { 'body' => {} } }
|
314
|
-
}
|
315
|
-
]
|
316
|
-
end
|
317
|
-
|
318
|
-
it 'should throw an appropriate error' do
|
319
|
-
expect { subject }.to raise_error do |e|
|
320
|
-
expect(e).to be_a(Elastic::AppSearch::BadRequest)
|
321
|
-
expect(e.errors).to eq(['Search fields contains invalid field: taco', 'Search fields contains invalid field: body'])
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
327
|
-
|
328
|
-
context 'QuerySuggest' do
|
329
|
-
describe '#query_suggestion' do
|
330
|
-
let(:query) { 'cat' }
|
331
|
-
let(:options) { { :size => 3, :types => { :documents => { :fields => ['title'] } } } }
|
332
|
-
|
333
|
-
context 'when options are provided' do
|
334
|
-
subject { @static_client.query_suggestion(@static_engine_name, query, options) }
|
335
|
-
|
336
|
-
it 'should request query suggestions' do
|
337
|
-
expect(subject).to match(
|
338
|
-
'meta' => anything,
|
339
|
-
'results' => anything
|
340
|
-
)
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
context 'when options are omitted' do
|
345
|
-
subject { @static_client.query_suggestion(@static_engine_name, query) }
|
346
|
-
|
347
|
-
it 'should request query suggestions' do
|
348
|
-
expect(subject).to match(
|
349
|
-
'meta' => anything,
|
350
|
-
'results' => anything
|
351
|
-
)
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
context 'SearchSettings' do
|
358
|
-
let(:default_settings) { {
|
359
|
-
"search_fields" => {
|
360
|
-
"id" => {
|
361
|
-
"weight" => 1
|
362
|
-
}
|
363
|
-
},
|
364
|
-
"result_fields" => {"id"=>{"raw"=>{}}},
|
365
|
-
"boosts" => {}
|
366
|
-
} }
|
367
|
-
|
368
|
-
let(:updated_settings) { {
|
369
|
-
"search_fields" => {
|
370
|
-
"id" => {
|
371
|
-
"weight" => 3
|
372
|
-
}
|
373
|
-
},
|
374
|
-
"result_fields" => {"id"=>{"raw"=>{}}},
|
375
|
-
"boosts" => {}
|
376
|
-
} }
|
377
|
-
|
378
|
-
before(:each) do
|
379
|
-
client.create_engine(engine_name) rescue Elastic::AppSearch::BadRequest
|
380
|
-
end
|
381
|
-
|
382
|
-
after(:each) do
|
383
|
-
client.destroy_engine(engine_name) rescue Elastic::AppSearch::NonExistentRecord
|
384
|
-
end
|
385
|
-
|
386
|
-
describe '#show_settings' do
|
387
|
-
subject { client.show_settings(engine_name) }
|
388
|
-
|
389
|
-
it 'should return default settings' do
|
390
|
-
expect(subject).to match(default_settings)
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
describe '#update_settings' do
|
395
|
-
subject { client.show_settings(engine_name) }
|
396
|
-
|
397
|
-
before do
|
398
|
-
client.update_settings(engine_name, updated_settings)
|
399
|
-
end
|
400
|
-
|
401
|
-
it 'should update search settings' do
|
402
|
-
expect(subject).to match(updated_settings)
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
describe '#reset_settings' do
|
407
|
-
subject { client.show_settings(engine_name) }
|
408
|
-
|
409
|
-
before do
|
410
|
-
client.update_settings(engine_name, updated_settings)
|
411
|
-
client.reset_settings(engine_name)
|
412
|
-
end
|
413
|
-
|
414
|
-
it 'should reset search settings' do
|
415
|
-
expect(subject).to match(default_settings)
|
416
|
-
end
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
context 'Engines' do
|
421
|
-
after do
|
422
|
-
client.destroy_engine(engine_name) rescue Elastic::AppSearch::NonExistentRecord
|
423
|
-
end
|
424
|
-
|
425
|
-
context '#create_engine' do
|
426
|
-
it 'should create an engine when given a right set of parameters' do
|
427
|
-
expect { client.get_engine(engine_name) }.to raise_error(Elastic::AppSearch::NonExistentRecord)
|
428
|
-
client.create_engine(engine_name)
|
429
|
-
expect { client.get_engine(engine_name) }.to_not raise_error
|
430
|
-
end
|
431
|
-
|
432
|
-
it 'should accept an optional language parameter' do
|
433
|
-
expect { client.get_engine(engine_name) }.to raise_error(Elastic::AppSearch::NonExistentRecord)
|
434
|
-
client.create_engine(engine_name, 'da')
|
435
|
-
expect(client.get_engine(engine_name)).to match('name' => anything, 'type' => anything, 'language' => 'da')
|
436
|
-
end
|
437
|
-
|
438
|
-
it 'should return an engine object' do
|
439
|
-
engine = client.create_engine(engine_name)
|
440
|
-
expect(engine).to be_kind_of(Hash)
|
441
|
-
expect(engine['name']).to eq(engine_name)
|
442
|
-
end
|
443
|
-
|
444
|
-
it 'should return an error when the engine name has already been taken' do
|
445
|
-
client.create_engine(engine_name)
|
446
|
-
expect { client.create_engine(engine_name) }.to raise_error do |e|
|
447
|
-
expect(e).to be_a(Elastic::AppSearch::BadRequest)
|
448
|
-
expect(e.errors).to eq(['Name is already taken'])
|
449
|
-
end
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
context '#list_engines' do
|
454
|
-
it 'should return an array with a list of engines' do
|
455
|
-
expect(client.list_engines['results']).to be_an(Array)
|
456
|
-
end
|
457
|
-
|
458
|
-
it 'should include the engine name in listed objects' do
|
459
|
-
client.create_engine(engine_name)
|
460
|
-
|
461
|
-
engines = client.list_engines['results']
|
462
|
-
expect(engines.find { |e| e['name'] == engine_name }).to_not be_nil
|
463
|
-
end
|
464
|
-
|
465
|
-
it 'should include the engine name in listed objects with pagination' do
|
466
|
-
client.create_engine(engine_name)
|
467
|
-
|
468
|
-
engines = client.list_engines(:current => 1, :size => 20)['results']
|
469
|
-
expect(engines.find { |e| e['name'] == engine_name }).to_not be_nil
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
context '#destroy_engine' do
|
474
|
-
it 'should destroy the engine if it exists' do
|
475
|
-
client.create_engine(engine_name)
|
476
|
-
expect { client.get_engine(engine_name) }.to_not raise_error
|
477
|
-
|
478
|
-
client.destroy_engine(engine_name)
|
479
|
-
expect { client.get_engine(engine_name) }.to raise_error(Elastic::AppSearch::NonExistentRecord)
|
480
|
-
end
|
481
|
-
|
482
|
-
it 'should raise an error if the engine does not exist' do
|
483
|
-
expect { client.destroy_engine(engine_name) }.to raise_error(Elastic::AppSearch::NonExistentRecord)
|
484
|
-
end
|
40
|
+
)
|
485
41
|
end
|
486
42
|
end
|
487
43
|
|
@@ -489,12 +45,12 @@ describe Elastic::AppSearch::Client do
|
|
489
45
|
context 'host_identifier' do
|
490
46
|
it 'sets the base url correctly' do
|
491
47
|
client = Elastic::AppSearch::Client.new(:host_identifier => 'host-asdf', :api_key => 'foo')
|
492
|
-
expect(client.api_endpoint).to
|
48
|
+
expect(client.api_endpoint).to(eq('https://host-asdf.api.swiftype.com/api/as/v1/'))
|
493
49
|
end
|
494
50
|
|
495
51
|
it 'sets the base url correctly using deprecated as_host_key' do
|
496
52
|
client = Elastic::AppSearch::Client.new(:account_host_key => 'host-asdf', :api_key => 'foo')
|
497
|
-
expect(client.api_endpoint).to
|
53
|
+
expect(client.api_endpoint).to(eq('https://host-asdf.api.swiftype.com/api/as/v1/'))
|
498
54
|
end
|
499
55
|
end
|
500
56
|
end
|