searchkick 3.1.1 → 3.1.2

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 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