search_flip 1.1.0 → 2.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 62b02c26a3579fdda9d1eca222c6c1eb19b28382
4
- data.tar.gz: fc3fe009dc1c8d84d03ab497c5302922474282c5
2
+ SHA256:
3
+ metadata.gz: 823b618d9cd15618f5e44b441644f281f1b5598feb11f52db75a538df78761ba
4
+ data.tar.gz: 3812f77dbcd670d76f9ae641f574035ff847c97b6c151f70f3fa663edf9619a6
5
5
  SHA512:
6
- metadata.gz: f6cee1c3258c0ff0662cec18d72313552706054e55a08c2f14003999c6d0d4bb910112507da340ad9dc1510b9f3f4b422ce11b0ec1b7eea8481450d430436bfc
7
- data.tar.gz: 9062e11098ab36c5063f992284a1d94ea27b422fabb0d4e94aa5b1c5b37da8c0508326d20566ab155f649034e2f924e739795b4ab89ab06ca6b2fa107f0e3bd3
6
+ metadata.gz: 2698a48a6c9e880a57776bd9bd39b21fdcbace96c5e1e50d12f81064dd3fb095d35c528c792d4f40951a9debde33dae4620928934e98596b3a32b2e9bb406c80
7
+ data.tar.gz: c4ba2b7c24f4096c98e3458e6c289c1ea7f9519f3f29ebf87d882f4d7600839c8ee96eb3c07efb76ff1fe3b738b39a0f7d9036a3682d86bc5751c71f26acdcc2
data/.rubocop.yml ADDED
@@ -0,0 +1,110 @@
1
+ Style/FrozenStringLiteralComment:
2
+ Enabled: false
3
+
4
+ Style/UnneededPercentQ:
5
+ Enabled: false
6
+
7
+ Style/BracesAroundHashParameters:
8
+ Enabled: false
9
+
10
+ Style/PercentLiteralDelimiters:
11
+ Enabled: false
12
+
13
+ Style/SpecialGlobalVars:
14
+ Enabled: false
15
+
16
+ Security/Eval:
17
+ Enabled: false
18
+
19
+ Style/WordArray:
20
+ Enabled: false
21
+
22
+ Style/ClassAndModuleChildren:
23
+ Enabled: false
24
+
25
+ Style/TrivialAccessors:
26
+ Enabled: false
27
+
28
+ Style/Alias:
29
+ Enabled: false
30
+
31
+ Style/StringLiteralsInInterpolation:
32
+ EnforcedStyle: double_quotes
33
+
34
+ Metrics/ClassLength:
35
+ Enabled: false
36
+
37
+ Naming/UncommunicativeMethodParamName:
38
+ Enabled: false
39
+
40
+ Style/SymbolArray:
41
+ Enabled: false
42
+
43
+ Layout/RescueEnsureAlignment:
44
+ Enabled: false
45
+
46
+ Layout/LeadingBlankLines:
47
+ Enabled: false
48
+
49
+ Metrics/LineLength:
50
+ Max: 150
51
+
52
+ Metrics/MethodLength:
53
+ Max: 60
54
+
55
+ Metrics/ModuleLength:
56
+ Enabled: false
57
+
58
+ Style/ZeroLengthPredicate:
59
+ Enabled: false
60
+
61
+ Layout/TrailingBlankLines:
62
+ Enabled: false
63
+
64
+ Metrics/PerceivedComplexity:
65
+ Enabled: false
66
+
67
+ Metrics/AbcSize:
68
+ Enabled: false
69
+
70
+ Metrics/CyclomaticComplexity:
71
+ Enabled: false
72
+
73
+ Metrics/BlockLength:
74
+ Max: 30
75
+
76
+ Metrics/BlockNesting:
77
+ Enabled: false
78
+
79
+ Style/NumericPredicate:
80
+ Enabled: false
81
+
82
+ Naming/AccessorMethodName:
83
+ Enabled: false
84
+
85
+ Naming/MemoizedInstanceVariableName:
86
+ Enabled: false
87
+
88
+ Style/StringLiterals:
89
+ EnforcedStyle: double_quotes
90
+
91
+ Style/Documentation:
92
+ Enabled: false
93
+
94
+ Naming/ConstantName:
95
+ Enabled: false
96
+
97
+ Style/MutableConstant:
98
+ Enabled: false
99
+
100
+ Layout/MultilineMethodCallIndentation:
101
+ EnforcedStyle: indented
102
+
103
+ Layout/AlignParameters:
104
+ EnforcedStyle: with_fixed_indentation
105
+
106
+ Lint/UnusedMethodArgument:
107
+ Enabled: false
108
+
109
+ Layout/IndentArray:
110
+ EnforcedStyle: consistent
data/.travis.yml CHANGED
@@ -1,36 +1,17 @@
1
1
 
2
+ sudo: false
3
+ language: ruby
4
+ env:
5
+ - ES_IMAGE=elasticsearch:1
6
+ - ES_IMAGE=plainpicture/elasticsearch:2.4.1_delete-by-query
7
+ - ES_IMAGE=elasticsearch:5.4
8
+ - ES_IMAGE=docker.elastic.co/elasticsearch/elasticsearch:6.5.0
2
9
  rvm:
3
- - 2.3.3
4
10
  - ruby-head
5
-
6
- dist: trusty
7
-
8
- jdk:
9
- - openjdk8
10
-
11
- env:
12
- - ES_VERSION=1
13
- - ES_VERSION=2
14
- - ES_VERSION=5
15
- - ES_VERSION=6
16
-
11
+ before_install:
12
+ - docker-compose up -d
13
+ - sleep 10
17
14
  install:
18
15
  - travis_retry bundle install
19
- - sh -c "if [ '$ES_VERSION' = '6' ]; then (curl -s https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.2.tar.gz | tar xz -C /tmp); fi"
20
- - sh -c "if [ '$ES_VERSION' = '6' ]; then /tmp/elasticsearch-6.2.2/bin/elasticsearch -d; fi"
21
- - sh -c "if [ '$ES_VERSION' = '5' ]; then (curl -s https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.0.tar.gz | tar xz -C /tmp); fi"
22
- - sh -c "if [ '$ES_VERSION' = '5' ]; then /tmp/elasticsearch-5.4.0/bin/elasticsearch -d; fi"
23
- - sh -c "if [ '$ES_VERSION' = '2' ]; then (curl -s https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.4.1/elasticsearch-2.4.1.tar.gz | tar xz -C /tmp); fi"
24
- - sh -c "if [ '$ES_VERSION' = '2' ]; then /tmp/elasticsearch-2.4.1/bin/plugin install delete-by-query; fi"
25
- - sh -c "if [ '$ES_VERSION' = '2' ]; then /tmp/elasticsearch-2.4.1/bin/elasticsearch -d; fi"
26
- - sh -c "if [ '$ES_VERSION' = '1' ]; then (curl -s https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.7.4.tar.gz | tar xz -C /tmp); fi"
27
- - sh -c "if [ '$ES_VERSION' = '1' ]; then /tmp/elasticsearch-1.7.4/bin/elasticsearch -d; fi"
28
-
29
- before_script:
30
- - sleep 30
31
-
32
- script:
33
- - rake test --trace
34
-
35
- sudo: false
16
+ script: rake test --trace
36
17
 
data/CHANGELOG.md CHANGED
@@ -1,10 +1,22 @@
1
1
 
2
2
  # CHANGELOG
3
3
 
4
- * Version 1.1.0
4
+ ## v2.0.0
5
5
 
6
- - Added `Criteria#find_results_in_batches` to scroll through the raw results
7
- - Fixed bug in `Criteria#find_in_batches` which possibly stopped scrolling too early
8
- - Added delegation for `should`, `should_not`, `must` and `must_not`
9
- - Migrated To FactoryBot
6
+ * **BREAKING**: Migration steps
7
+ * Change `SearchFlip.version` to `SearchFlip::Connection#version`
8
+ * Change `SearchFlip.msearch` to `SearchFlip::Connection#msearch`
9
+ * Change `SearchFlip.aliases` to `SearchFlip::Connection#update_aliases`
10
+ * Change `SearchFlip::Criteria#execute(base_url: '...')` to `SearchFlip::Criteria#execute(connection: SearchFlip::Connection.new(base_url: '...'))`
11
+ * Added `SearchFlip::Connection`
12
+ * Added `SearchFlip::Connection#update_aliases`
13
+ * Added `SearchFlip::Connection#get_aliases`
14
+ * Added `SearchFlip::Connection#alias_exists?`
15
+
16
+ ## v1.1.0
17
+
18
+ * Added `Criteria#find_results_in_batches` to scroll through the raw results
19
+ * Fixed bug in `Criteria#find_in_batches` which possibly stopped scrolling too early
20
+ * Added delegation for `should`, `should_not`, `must` and `must_not`
21
+ * Migrated To FactoryBot
10
22
 
data/README.md CHANGED
@@ -501,6 +501,24 @@ CommentIndex.terminate_after(10).execute
501
501
 
502
502
  For further details and a full list of methods, check out the reference docs.
503
503
 
504
+ ## Using multiple Elasticsearch clusters
505
+
506
+ To use multiple Elasticsearch clusters, specify a connection within your
507
+ indices:
508
+
509
+ ```ruby
510
+ class MyIndex
511
+ include SearchFlip::Index
512
+
513
+ def self.connection
514
+ @connection ||= SearchFlip::Connection.new(base_url: "http://elasticsearch.host:9200")
515
+ end
516
+ end
517
+ ```
518
+
519
+ This allows to use different clusters per index e.g. when migrating indices to
520
+ new versions of Elasticsearch.
521
+
504
522
  ## Non-ActiveRecord models
505
523
 
506
524
  SearchFlip ships with built-in support for ActiveRecord models, but using
@@ -618,3 +636,17 @@ model changes.
618
636
  4. Push to the branch (`git push origin my-new-feature`)
619
637
  5. Create new Pull Request
620
638
 
639
+ ## Running the test suite
640
+
641
+ Running the tests is super easy. The test suite uses sqlite, such that you only
642
+ need to install ElasticSearch. You can install ElasticSearch on your own, or
643
+ you can e.g. use docker-compose:
644
+
645
+ ```
646
+ $ cd search_flip
647
+ $ sudo ES_IMAGE=elasticsearch:5.4 docker-compose up
648
+ $ rake test
649
+ ```
650
+
651
+ That's it.
652
+
@@ -0,0 +1,6 @@
1
+ version: '2'
2
+ services:
3
+ elasticsearch:
4
+ image: $ES_IMAGE
5
+ ports:
6
+ - 9200:9200
data/lib/search_flip.rb CHANGED
@@ -6,9 +6,11 @@ require "oj"
6
6
  require "set"
7
7
 
8
8
  require "search_flip/version"
9
+ require "search_flip/exceptions"
9
10
  require "search_flip/json"
10
11
  require "search_flip/http_client"
11
12
  require "search_flip/config"
13
+ require "search_flip/connection"
12
14
  require "search_flip/bulk"
13
15
  require "search_flip/filterable"
14
16
  require "search_flip/post_filterable"
@@ -36,47 +38,5 @@ module SearchFlip
36
38
  "#{self.class.name} (#{code}): #{body}"
37
39
  end
38
40
  end
39
-
40
- # Uses the ElasticSearch Multi Search API to execute multiple search requests
41
- # within a single request. Raises SearchFlip::ResponseError in case any
42
- # errors occur.
43
- #
44
- # @example
45
- # SearchFlip.msearch [ProductIndex.match_all, CommentIndex.match_all]
46
- #
47
- # @param criterias [Array<SearchFlip::Criteria>] An array of search
48
- # queries to execute in parallel
49
- #
50
- # @return [Array<SearchFlip::Response>] An array of responses
51
-
52
- def self.msearch(criterias)
53
- payload = criterias.flat_map do |criteria|
54
- [SearchFlip::JSON.generate(index: criteria.target.index_name_with_prefix, type: criteria.target.type_name), SearchFlip::JSON.generate(criteria.request)]
55
- end
56
-
57
- payload = payload.join("\n")
58
- payload << "\n"
59
-
60
- SearchFlip::HTTPClient.headers(accept: "application/json", content_type: "application/x-ndjson").post("#{SearchFlip::Config[:base_url]}/_msearch", body: payload).parse["responses"].map.with_index do |response, index|
61
- SearchFlip::Response.new(criterias[index], response)
62
- end
63
- end
64
-
65
- # Used to manipulate, ie add and remove index aliases. Raises an
66
- # SearchFlip::ResponseError in case any errors occur.
67
- #
68
- # @example
69
- # ElasticSearch.post_aliases(actions: [
70
- # { remove: { index: "test1", alias: "alias1" }},
71
- # { add: { index: "test2", alias: "alias1" }}
72
- # ])
73
- #
74
- # @param payload [Hash] The raw request payload
75
- #
76
- # @return [SearchFlip::Response] The raw response
77
-
78
- def self.aliases(payload)
79
- SearchFlip::HTTPClient.headers(accept: "application/json", content_type: "application/json").post("#{SearchFlip::Config[:base_url]}/_aliases", body: SearchFlip::JSON.generate(payload))
80
- end
81
41
  end
82
42
 
@@ -56,7 +56,7 @@ module SearchFlip
56
56
  hash = field_or_hash.is_a?(Hash) ? field_or_hash : { field_or_hash => { terms: { field: field_or_hash }.merge(options) } }
57
57
 
58
58
  if block
59
- aggregation = block.call(SearchFlip::Aggregation.new)
59
+ aggregation = yield(SearchFlip::Aggregation.new(target: target))
60
60
 
61
61
  field_or_hash.is_a?(Hash) ? hash[field_or_hash.keys.first].merge!(aggregation.to_hash) : hash[field_or_hash].merge!(aggregation.to_hash)
62
62
  end
@@ -8,6 +8,12 @@ module SearchFlip
8
8
  include SearchFlip::Filterable
9
9
  include SearchFlip::Aggregatable
10
10
 
11
+ attr_reader :target
12
+
13
+ def initialize(target:)
14
+ @target = target
15
+ end
16
+
11
17
  # @api private
12
18
  #
13
19
  # Converts the aggregation to a hash format that can be used in the request.
@@ -19,20 +25,20 @@ module SearchFlip
19
25
  res[:aggregations] = aggregation_values if aggregation_values
20
26
 
21
27
  if must_values || search_values || must_not_values || should_values || filter_values
22
- if SearchFlip.version.to_i >= 2
28
+ if target.connection.version.to_i >= 2
23
29
  res[:filter] = {
24
- bool: {}.
25
- merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {}).
26
- merge(must_not_values ? { must_not: must_not_values } : {}).
27
- merge(should_values ? { should: should_values } : {}).
28
- merge(filter_values ? { filter: filter_values } : {})
30
+ bool: {}
31
+ .merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {})
32
+ .merge(must_not_values ? { must_not: must_not_values } : {})
33
+ .merge(should_values ? { should: should_values } : {})
34
+ .merge(filter_values ? { filter: filter_values } : {})
29
35
  }
30
36
  else
31
37
  filters = (filter_values || []) + (must_not_values || []).map { |must_not_value| { not: must_not_value } }
32
38
 
33
- queries = {}.
34
- merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {}).
35
- merge(should_values ? { should: should_values } : {})
39
+ queries = {}
40
+ .merge(must_values || search_values ? { must: (must_values || []) + (search_values || []) } : {})
41
+ .merge(should_values ? { should: should_values } : {})
36
42
 
37
43
  filters_and_queries = filters + (queries.size > 0 ? [bool: queries] : [])
38
44
 
@@ -113,7 +113,10 @@ module SearchFlip
113
113
  end
114
114
 
115
115
  def upload
116
- response = SearchFlip::HTTPClient.headers(accept: "application/json", content_type: "application/x-ndjson").put(url, body: @payload, params: ignore_errors ? {} : { filter_path: "errors" })
116
+ response =
117
+ SearchFlip::HTTPClient
118
+ .headers(accept: "application/json", content_type: "application/x-ndjson")
119
+ .put(url, body: @payload, params: ignore_errors ? {} : { filter_path: "errors" })
117
120
 
118
121
  return if options[:raise] == false
119
122
 
@@ -121,13 +124,13 @@ module SearchFlip
121
124
 
122
125
  return unless parsed_response["errors"]
123
126
 
124
- raise(SearchFlip::Bulk::Error, response[0 .. 30]) unless ignore_errors
127
+ raise(SearchFlip::Bulk::Error, response[0..30]) unless ignore_errors
125
128
 
126
129
  parsed_response["items"].each do |item|
127
- item.each do |_, _item|
128
- status = _item["status"]
130
+ item.each do |_, element|
131
+ status = element["status"]
129
132
 
130
- raise(SearchFlip::Bulk::Error, SearchFlip::JSON.generate(_item)) if !status.between?(200, 299) && !ignore_errors.include?(status)
133
+ raise(SearchFlip::Bulk::Error, SearchFlip::JSON.generate(element)) if !status.between?(200, 299) && !ignore_errors.include?(status)
131
134
  end
132
135
  end
133
136
  ensure
@@ -1,16 +1,5 @@
1
1
 
2
2
  module SearchFlip
3
- # Queries and returns the ElasticSearch version used.
4
- #
5
- # @example
6
- # SearchFlip.version # => e.g. 2.4.1
7
- #
8
- # @return [String] The ElasticSearch version
9
-
10
- def self.version
11
- @version ||= SearchFlip::HTTPClient.get("#{Config[:base_url]}/").parse["version"]["number"]
12
- end
13
-
14
3
  Config = {
15
4
  index_prefix: nil,
16
5
  base_url: "http://127.0.0.1:9200",
@@ -0,0 +1,131 @@
1
+
2
+ module SearchFlip
3
+ class Connection
4
+ attr_reader :base_url
5
+
6
+ def initialize(base_url: SearchFlip::Config[:base_url])
7
+ @base_url = base_url
8
+ end
9
+
10
+ # Queries and returns the ElasticSearch version used.
11
+ #
12
+ # @example
13
+ # connection.version # => e.g. 2.4.1
14
+ #
15
+ # @return [String] The ElasticSearch version
16
+
17
+ def version
18
+ @version ||= SearchFlip::HTTPClient.get("#{base_url}/").parse["version"]["number"]
19
+ end
20
+
21
+ # Uses the ElasticSearch Multi Search API to execute multiple search requests
22
+ # within a single request. Raises SearchFlip::ResponseError in case any
23
+ # errors occur.
24
+ #
25
+ # @example
26
+ # connection.msearch [ProductIndex.match_all, CommentIndex.match_all]
27
+ #
28
+ # @param criterias [Array<SearchFlip::Criteria>] An array of search
29
+ # queries to execute in parallel
30
+ #
31
+ # @return [Array<SearchFlip::Response>] An array of responses
32
+
33
+ def msearch(criterias)
34
+ payload = criterias.flat_map do |criteria|
35
+ [
36
+ SearchFlip::JSON.generate(index: criteria.target.index_name_with_prefix, type: criteria.target.type_name),
37
+ SearchFlip::JSON.generate(criteria.request)
38
+ ]
39
+ end
40
+
41
+ payload = payload.join("\n")
42
+ payload << "\n"
43
+
44
+ raw_response =
45
+ SearchFlip::HTTPClient
46
+ .headers(accept: "application/json", content_type: "application/x-ndjson")
47
+ .post("#{base_url}/_msearch", body: payload)
48
+
49
+ raw_response.parse["responses"].map.with_index do |response, index|
50
+ SearchFlip::Response.new(criterias[index], response)
51
+ end
52
+ end
53
+
54
+ # Used to manipulate, ie add and remove index aliases. Raises an
55
+ # SearchFlip::ResponseError in case any errors occur.
56
+ #
57
+ # @example
58
+ # connection.update_aliases(actions: [
59
+ # { remove: { index: "test1", alias: "alias1" }},
60
+ # { add: { index: "test2", alias: "alias1" }}
61
+ # ])
62
+ #
63
+ # @param payload [Hash] The raw request payload
64
+ #
65
+ # @return [Hash] The raw response
66
+
67
+ def update_aliases(payload)
68
+ SearchFlip::HTTPClient
69
+ .headers(accept: "application/json", content_type: "application/json")
70
+ .post("#{base_url}/_aliases", body: SearchFlip::JSON.generate(payload))
71
+ .parse
72
+ end
73
+
74
+ # Fetches information about the specified index aliases. Raises
75
+ # SearchFlip::ResponseError in case any errors occur.
76
+ #
77
+ # @example
78
+ # connection.get_aliases(alias_name: "some_alias")
79
+ # connection.get_aliases(index_name: "index1,index2")
80
+ #
81
+ # @param alias_name [String] The alias or comma separated list of alias names
82
+ # @param index_name [String] The index or comma separated list of index names
83
+ #
84
+ # @return [Hash] The raw response
85
+
86
+ def get_aliases(index_name: "*", alias_name: "*")
87
+ res = SearchFlip::HTTPClient
88
+ .headers(accept: "application/json", content_type: "application/json")
89
+ .get("#{base_url}/#{index_name}/_alias/#{alias_name}")
90
+ .parse
91
+
92
+ Hashie::Mash.new(res)
93
+ end
94
+
95
+ # Returns whether or not the associated ElasticSearch alias already
96
+ # exists.
97
+ #
98
+ # @example
99
+ # connection.alias_exists?("some_alias")
100
+ #
101
+ # @return [Boolean] Whether or not the alias exists
102
+
103
+ def alias_exists?(alias_name)
104
+ SearchFlip::HTTPClient
105
+ .headers(accept: "application/json", content_type: "application/json")
106
+ .get("#{base_url}/_alias/#{alias_name}")
107
+
108
+ true
109
+ rescue SearchFlip::ResponseError => e
110
+ return false if e.code == 404
111
+
112
+ raise e
113
+ end
114
+
115
+ # Fetches information about the specified indices. Raises
116
+ # SearchFlip::ResponseError in case any errors occur.
117
+ #
118
+ # @example
119
+ # connection.get_indices('prefix*')
120
+ #
121
+ # @return [Array] The raw response
122
+
123
+ def get_indices(name = "*")
124
+ SearchFlip::HTTPClient
125
+ .headers(accept: "application/json", content_type: "application/json")
126
+ .get("#{base_url}/_cat/indices/#{name}")
127
+ .parse
128
+ end
129
+ end
130
+ end
131
+