searchkick 3.1.1 → 3.1.2

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
2
  SHA256:
3
- metadata.gz: b778411135d61db33ef8f82eb06990b41502d53cd5b2f4a21579f8c79b2f7aff
4
- data.tar.gz: ba732ab1e72db7a9c5600bf99c3ae4b99d91cb47c97ad3ada0147888cb5e084f
3
+ metadata.gz: bfa26cdc7332a0b73376d46fbd9b66cc093e919d605bbd80ceec04cfbffed914
4
+ data.tar.gz: 541e111f81bec56c621b147e5aea2b8017a91eaa3f40d074d1a5aa619da14f14
5
5
  SHA512:
6
- metadata.gz: e4bb9b36b02989e29ed8adf179f45abf597ff91a63e23f442ab285f05523f15d8e00ff7a6fc634fca5553d6d91a05be467e589f8cf6e1b0de155b6db81c623fb
7
- data.tar.gz: 417adb5009b35512b45c11024e4c9a413d713361a2bb0897b17e8c9128a788bcbb3b8df7801ef50a0fbae8269741e8a5f3c2405b4ddcdd0dab9f1ef914ef28bd
6
+ metadata.gz: ea250f38b93967d245168ab5b0cbb41a86fb0d471df8f5844e2f3e59337630b8a545df059b5fe08fb7582046749e0ffebc2b8d9152e7eee225e04ad7aedb5a54
7
+ data.tar.gz: 07f98bb46fd861dc9957ff81931965c3032dccada46e098c9723bcba68fe9365b9927c6d1283ae564aa96f83eaccdd547356de6cf3ccec7fde699a9b9d3ef18e
@@ -1,3 +1,11 @@
1
+ ## 3.1.2
2
+
3
+ - Improved performance of indices boost
4
+ - Fixed deletes with routing and `async` callbacks
5
+ - Fixed deletes with routing and `queue` callbacks
6
+ - Fixed deprecation warnings
7
+ - Fixed field misspellings for older partial match format
8
+
1
9
  ## 3.1.1
2
10
 
3
11
  - Added per-field misspellings
data/README.md CHANGED
@@ -30,7 +30,7 @@ Plus:
30
30
 
31
31
  ---
32
32
 
33
- Does your startup use Searchkick? Want a free hour of advising? Fill out [this application](https://goo.gl/forms/Or1HQTRb2rgQCNtd2). I’ll reach out to a few companies.
33
+ Does your company use Searchkick? Want free advising? Fill out [this application](https://goo.gl/forms/Or1HQTRb2rgQCNtd2)
34
34
 
35
35
  ---
36
36
 
@@ -46,10 +46,6 @@ Does your startup use Searchkick? Want a free hour of advising? Fill out [this a
46
46
  - [Elasticsearch DSL](#advanced)
47
47
  - [Reference](#reference)
48
48
 
49
- **Searchkick 3.0 was recently released!** See [how to upgrade](docs/Searchkick-3-Upgrade.md)
50
-
51
- Thinking of upgrading from Elasticsearch 5 to 6? [Read this first](#elasticsearch-5-to-6-upgrade)
52
-
53
49
  ## Getting Started
54
50
 
55
51
  [Install Elasticsearch](https://www.elastic.co/guide/en/elasticsearch/reference/current/setup.html). For Homebrew, use:
@@ -439,6 +435,12 @@ exclude_queries = {
439
435
  Product.search query, exclude: exclude_queries[query]
440
436
  ```
441
437
 
438
+ You can demote results by boosting by a factor less than one:
439
+
440
+ ```ruby
441
+ Product.search("butter", boost_where: {category: {value: "pantry", factor: 0.5}})
442
+ ```
443
+
442
444
  ### Emoji
443
445
 
444
446
  Search :ice_cream::cake: and get `ice cream cake`!
@@ -776,9 +778,11 @@ Product.search "apples", aggs: {store_id: {limit: 10}}
776
778
  Order
777
779
 
778
780
  ```ruby
779
- Product.search "wingtips", aggs: {color: {order: {"_term" => "asc"}}} # alphabetically
781
+ Product.search "wingtips", aggs: {color: {order: {"_key" => "asc"}}} # alphabetically
780
782
  ```
781
783
 
784
+ **Note:** Use `_term` instead of `_key` in Elasticsearch 5
785
+
782
786
  [All of these options are supported](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-order)
783
787
 
784
788
  Ranges
@@ -800,6 +804,8 @@ Script support
800
804
  Product.search "*", aggs: {color: {script: {source: "'Color: ' + _value"}}}
801
805
  ```
802
806
 
807
+ **Note:** Use `inline` instead of `source` before Elasticsearch 5.6
808
+
803
809
  Date histogram
804
810
 
805
811
  ```ruby
@@ -999,11 +1005,14 @@ Dog.search "*" # just dogs
999
1005
  Animal.search "*", type: [Dog, Cat] # just cats and dogs
1000
1006
  ```
1001
1007
 
1002
- **Note:** The `suggest` option retrieves suggestions from the parent at the moment.
1008
+ **Notes:**
1003
1009
 
1004
- ```ruby
1005
- Dog.search "airbudd", suggest: true # suggestions for all animals
1006
- ```
1010
+ 1. The `suggest` option retrieves suggestions from the parent at the moment.
1011
+
1012
+ ```ruby
1013
+ Dog.search "airbudd", suggest: true # suggestions for all animals
1014
+ ```
1015
+ 2. This relies on a `type` field that is automatically added to the indexed document. Be wary of defining your own `type` field in `search_data`, as it will take precedence.
1007
1016
 
1008
1017
  ## Debugging Queries
1009
1018
 
@@ -1732,6 +1741,16 @@ Create index without importing
1732
1741
  Product.reindex(import: false)
1733
1742
  ```
1734
1743
 
1744
+ Use a different id
1745
+
1746
+ ```ruby
1747
+ class Product < ApplicationRecord
1748
+ def search_document_id
1749
+ custom_id
1750
+ end
1751
+ end
1752
+ ```
1753
+
1735
1754
  Lazy searching
1736
1755
 
1737
1756
  ```ruby
@@ -1887,6 +1906,10 @@ Searchkick.index_suffix = ENV["TEST_ENV_NUMBER"]
1887
1906
 
1888
1907
  Check out [this great post](https://www.tiagoamaro.com.br/2014/12/11/multi-tenancy-with-searchkick/) on the [Apartment](https://github.com/influitive/apartment) gem. Follow a similar pattern if you use another gem.
1889
1908
 
1909
+ ## Upgrading
1910
+
1911
+ See [how to upgrade to Searchkick 3](docs/Searchkick-3-Upgrade.md)
1912
+
1890
1913
  ## Elasticsearch 5 to 6 Upgrade
1891
1914
 
1892
1915
  Elasticsearch 6 removes the ability to reindex with the `_all` field. Before you upgrade, we recommend disabling this field manually and specifying default fields on your models.
@@ -3,6 +3,10 @@ module Searchkick
3
3
  queue_as { Searchkick.queue_name }
4
4
 
5
5
  def perform(class_name:, record_ids:)
6
+ # separate routing from id
7
+ routing = Hash[record_ids.map { |r| r.split(/(?<!\|)\|(?!\|)/, 2).map { |v| v.gsub("||", "|") } }]
8
+ record_ids = routing.keys
9
+
6
10
  klass = class_name.constantize
7
11
  scope = Searchkick.load_records(klass, record_ids)
8
12
  scope = scope.search_import if scope.respond_to?(:search_import)
@@ -10,7 +14,16 @@ module Searchkick
10
14
 
11
15
  # determine which records to delete
12
16
  delete_ids = record_ids - records.map { |r| r.id.to_s }
13
- delete_records = delete_ids.map { |id| m = klass.new; m.id = id; m }
17
+ delete_records = delete_ids.map do |id|
18
+ m = klass.new
19
+ m.id = id
20
+ if routing[id]
21
+ m.define_singleton_method(:search_routing) do
22
+ routing[id]
23
+ end
24
+ end
25
+ m
26
+ end
14
27
 
15
28
  # bulk reindex
16
29
  index = klass.searchkick_index
@@ -281,10 +281,10 @@ module Searchkick
281
281
  prefix_length = (misspellings.is_a?(Hash) && misspellings[:prefix_length]) || 0
282
282
  default_max_expansions = @misspellings_below ? 20 : 3
283
283
  max_expansions = (misspellings.is_a?(Hash) && misspellings[:max_expansions]) || default_max_expansions
284
- misspellings_fields = misspellings.is_a?(Hash) && misspellings.key?(:fields) && misspellings[:fields].map { |f| "#{f}.#{@match_suffix}" }
284
+ misspellings_fields = misspellings.is_a?(Hash) && misspellings.key?(:fields) && misspellings[:fields].map(&:to_s)
285
285
 
286
286
  if misspellings_fields
287
- missing_fields = misspellings_fields - fields
287
+ missing_fields = misspellings_fields - fields.map { |f| base_field(f) }
288
288
  if missing_fields.any?
289
289
  raise ArgumentError, "All fields in per-field misspellings must also be specified in fields option"
290
290
  end
@@ -324,7 +324,7 @@ module Searchkick
324
324
  exclude_analyzer = nil
325
325
  exclude_field = field
326
326
 
327
- field_misspellings = misspellings && (!misspellings_fields || misspellings_fields.include?(field))
327
+ field_misspellings = misspellings && (!misspellings_fields || misspellings_fields.include?(base_field(field)))
328
328
 
329
329
  if field == "_all" || field.end_with?(".analyzed")
330
330
  shared_options[:cutoff_frequency] = 0.001 unless operator.to_s == "and" || field_misspellings == false
@@ -660,11 +660,20 @@ module Searchkick
660
660
  def set_boost_by_indices(payload)
661
661
  return unless options[:indices_boost]
662
662
 
663
- indices_boost = options[:indices_boost].each_with_object({}) do |(key, boost), memo|
664
- index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key
665
- # try to use index explicitly instead of alias: https://github.com/elasticsearch/elasticsearch/issues/4756
666
- index_by_alias = Searchkick.client.indices.get_alias(index: index).keys.first
667
- memo[index_by_alias || index] = boost
663
+ if below52?
664
+ indices_boost = options[:indices_boost].each_with_object({}) do |(key, boost), memo|
665
+ index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key
666
+ # try to use index explicitly instead of alias: https://github.com/elasticsearch/elasticsearch/issues/4756
667
+ index_by_alias = Searchkick.client.indices.get_alias(index: index).keys.first
668
+ memo[index_by_alias || index] = boost
669
+ end
670
+ else
671
+ # array format supports alias resolution
672
+ # https://github.com/elastic/elasticsearch/pull/21393
673
+ indices_boost = options[:indices_boost].map do |key, boost|
674
+ index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key
675
+ {index => boost}
676
+ end
668
677
  end
669
678
 
670
679
  payload[:indices_boost] = indices_boost
@@ -812,7 +821,7 @@ module Searchkick
812
821
  # TODO id transformation for arrays
813
822
  def set_order(payload)
814
823
  order = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc}
815
- id_field = :_uid
824
+ id_field = below60? ? :_uid : :_id
816
825
  payload[:sort] = order.is_a?(Array) ? order : Hash[order.map { |k, v| [k.to_s == "id" ? id_field : k, v] }]
817
826
  end
818
827
 
@@ -998,6 +1007,14 @@ module Searchkick
998
1007
  end
999
1008
  end
1000
1009
 
1010
+ def base_field(k)
1011
+ k.sub(/\.(analyzed|word_start|word_middle|word_end|text_start|text_middle|text_end|exact)\z/, "")
1012
+ end
1013
+
1014
+ def below52?
1015
+ Searchkick.server_below?("5.2.0")
1016
+ end
1017
+
1001
1018
  def below60?
1002
1019
  Searchkick.server_below?("6.0.0")
1003
1020
  end
@@ -34,6 +34,11 @@ module Searchkick
34
34
  index.klass_document_type(record.class, ignore_type)
35
35
  end
36
36
 
37
+ # memoize
38
+ def self.routing_key
39
+ @routing_key ||= Searchkick.server_below?("6.0.0") ? :_routing : :routing
40
+ end
41
+
37
42
  private
38
43
 
39
44
  def record_data
@@ -42,7 +47,7 @@ module Searchkick
42
47
  _id: search_id,
43
48
  _type: document_type
44
49
  }
45
- data[:_routing] = record.search_routing if record.respond_to?(:search_routing)
50
+ data[self.class.routing_key] = record.search_routing if record.respond_to?(:search_routing)
46
51
  data
47
52
  end
48
53
 
@@ -20,16 +20,32 @@ module Searchkick
20
20
  raise Searchkick::Error, "Partial reindex not supported with queue option"
21
21
  end
22
22
 
23
- index.reindex_queue.push(record.id.to_s)
23
+ # always pass routing in case record is deleted
24
+ # before the queue job runs
25
+ if record.respond_to?(:search_routing)
26
+ routing = record.search_routing
27
+ end
28
+
29
+ # escape pipe with double pipe
30
+ value = queue_escape(record.id.to_s)
31
+ value = "#{value}|#{queue_escape(routing)}" if routing
32
+ index.reindex_queue.push(value)
24
33
  when :async
25
34
  unless defined?(ActiveJob)
26
35
  raise Searchkick::Error, "Active Job not found"
27
36
  end
28
37
 
38
+ # always pass routing in case record is deleted
39
+ # before the async job runs
40
+ if record.respond_to?(:search_routing)
41
+ routing = record.search_routing
42
+ end
43
+
29
44
  Searchkick::ReindexV2Job.perform_later(
30
45
  record.class.name,
31
46
  record.id.to_s,
32
- method_name ? method_name.to_s : nil
47
+ method_name ? method_name.to_s : nil,
48
+ routing: routing
33
49
  )
34
50
  else # bulk, inline/true/nil
35
51
  reindex_record(method_name)
@@ -40,6 +56,10 @@ module Searchkick
40
56
 
41
57
  private
42
58
 
59
+ def queue_escape(value)
60
+ value.gsub("|", "||")
61
+ end
62
+
43
63
  def reindex_record(method_name)
44
64
  if record.destroyed? || !record.persisted? || !record.should_index?
45
65
  begin
@@ -9,7 +9,7 @@ module Searchkick
9
9
 
10
10
  queue_as { Searchkick.queue_name }
11
11
 
12
- def perform(klass, id, method_name = nil)
12
+ def perform(klass, id, method_name = nil, routing: nil)
13
13
  model = klass.constantize
14
14
  record =
15
15
  begin
@@ -28,6 +28,11 @@ module Searchkick
28
28
  unless record
29
29
  record = model.new
30
30
  record.id = id
31
+ if routing
32
+ record.define_singleton_method(:search_routing) do
33
+ routing
34
+ end
35
+ end
31
36
  end
32
37
 
33
38
  RecordIndexer.new(record).reindex(method_name, mode: :inline)
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "3.1.1"
2
+ VERSION = "3.1.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.1
4
+ version: 3.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-09 00:00:00.000000000 Z
11
+ date: 2018-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel