diff --git a/.travis.yml b/.travis.yml index 674768b..1e6fe67 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,30 +14,24 @@ cache: directories: - $HOME/elasticsearch env: - - ELASTICSEARCH_VERSION=6.7.0 + - ELASTICSEARCH_VERSION=7.0.0 jdk: openjdk10 matrix: include: - gemfile: Gemfile - gemfile: test/gemfiles/activerecord51.gemfile - env: ELASTICSEARCH_VERSION=6.0.0 + env: ELASTICSEARCH_VERSION=7.0.0 - gemfile: test/gemfiles/activerecord50.gemfile - env: ELASTICSEARCH_VERSION=5.6.10 - - gemfile: test/gemfiles/activerecord42.gemfile - env: ELASTICSEARCH_VERSION=5.0.1 - - gemfile: test/gemfiles/mongoid6.gemfile + env: ELASTICSEARCH_VERSION=6.7.0 + - gemfile: test/gemfiles/mongoid7.gemfile + env: ELASTICSEARCH_VERSION=6.0.0 services: - mongodb - redis-server - - gemfile: test/gemfiles/mongoid5.gemfile + - gemfile: test/gemfiles/mongoid6.gemfile services: - mongodb - redis-server - - gemfile: Gemfile - env: ELASTICSEARCH_VERSION=7.0.0-rc1 - allow_failures: - - gemfile: Gemfile - env: ELASTICSEARCH_VERSION=7.0.0-rc1 notifications: email: on_success: never diff --git a/CHANGELOG.md b/CHANGELOG.md index d5c3203..a026154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 4.0.0 [unreleased] + +- Added support for Elasticsearch 7 +- Added `models` option + +Breaking changes + +- Removed support for Elasticsearch 5 +- Removed support for multi-word synonyms (they no longer work with shingles) + ## 3.1.3 - Added support for endless ranges diff --git a/README.md b/README.md index 1189368..904c7af 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Add this line to your application’s Gemfile: gem 'searchkick' ``` -The latest version works with Elasticsearch 5 and 6. For Elasticsearch 2, use version 2.5.0 and [this readme](https://github.com/ankane/searchkick/blob/v2.5.0/README.md). +The latest version works with Elasticsearch 6 and 7. For Elasticsearch 5, use version 3.1.3 and [this readme](https://github.com/ankane/searchkick/blob/v3.1.3/README.md). Add searchkick to models you want to search. @@ -312,13 +312,13 @@ A few languages require plugins: ```ruby class Product < ApplicationRecord - searchkick synonyms: [["scallion", "green onion"], ["qtip", "cotton swab"]] + searchkick synonyms: [["burger", "hamburger"], ["sneakers", "shoes"]] end ``` Call `Product.reindex` after changing synonyms. -Synonyms cannot be more than two words at the moment. +Synonyms cannot be multiple words at the moment. To read synonyms from a file, use: @@ -796,8 +796,6 @@ Script support Product.search "*", aggs: {color: {script: {source: "'Color: ' + _value"}}} ``` -**Note:** Use `inline` instead of `source` before Elasticsearch 5.6 - Date histogram ```ruby @@ -924,9 +922,7 @@ You can also index and search geo shapes. ```ruby class Restaurant < ApplicationRecord - searchkick geo_shape: { - bounds: {tree: "geohash", precision: "1km"} - } + searchkick geo_shape: [:bounds] def search_data attributes.merge( @@ -959,12 +955,6 @@ Not touching the query shape Restaurant.search "burger", where: {bounds: {geo_shape: {type: "envelope", relation: "disjoint", coordinates: [{lat: 38, lon: -123}, {lat: 37, lon: -122}]}}} ``` -Containing the query shape - -```ruby -Restaurant.search "fries", where: {bounds: {geo_shape: {type: "envelope", relation: "contains", coordinates: [{lat: 38, lon: -123}, {lat: 37, lon: -122}]}}} -``` - ## Inheritance Searchkick supports single table inheritance. @@ -1496,21 +1486,15 @@ Then use `products` and `coupons` as typical results. **Note:** Errors are not raised as with single requests. Use the `error` method on each query to check for errors. -## Multiple Indices +## Multiple Models -Search across multiple models/indices with: +Search across multiple models with: ```ruby -Searchkick.search "milk", index_name: [Product, Category] +Searchkick.search "milk", models: [Product, Category] ``` -Specify conditions for different indices - -```ruby -where: {_or: [{_type: "product", in_stock: true}, {_type: "category", active: true}]} -``` - -Boost specific indices with: +Boost specific models with: ```ruby indices_boost: {Category => 2, Product => 1} @@ -1657,7 +1641,7 @@ Product.search "milk", includes: [:brand, :stores] Eager load different associations by model ```ruby -Searchkick.search("*", index_name: [Product, Store], model_includes: {Product => [:store], Store => [:product]}) +Searchkick.search("*", models: [Product, Store], model_includes: {Product => [:store], Store => [:product]}) ``` Run additional scopes on results @@ -1900,6 +1884,11 @@ Check out [this great post](https://www.tiagoamaro.com.br/2014/12/11/multi-tenan See [how to upgrade to Searchkick 3](docs/Searchkick-3-Upgrade.md) +## Elasticsearch 6 to 7 Upgrade + +1. Install Searchkick 4 +2. Upgrade your Elasticsearch cluster + ## Elasticsearch 5 to 6 Upgrade 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. diff --git a/lib/searchkick.rb b/lib/searchkick.rb index 44753c6..99a3728 100644 --- a/lib/searchkick.rb +++ b/lib/searchkick.rb @@ -78,16 +78,36 @@ module Searchkick Gem::Version.new(server_version.split("-")[0]) < Gem::Version.new(version.split("-")[0]) end + # memoize for performance + def self.server_below7? + unless defined?(@server_below7) + @server_below7 = server_below?("7.0.0") + end + @server_below7 + end + def self.search(term = "*", model: nil, **options, &block) options = options.dup klass = model - # make Searchkick.search(index_name: [Product]) and Product.search equivalent + # convert index_name into models if possible + # this should allow for easier upgrade + if options[:index_name] && !options[:models] && Array(options[:index_name]).all? { |v| v.respond_to?(:searchkick_index) } + options[:models] = options.delete(:index_name) + end + + # make Searchkick.search(models: [Product]) and Product.search equivalent unless klass - index_name = Array(options[:index_name]) - if index_name.size == 1 && index_name.first.respond_to?(:searchkick_index) - klass = index_name.first - options.delete(:index_name) + models = Array(options[:models]) + if models.size == 1 + klass = models.first + options.delete(:models) + end + end + + if klass + if (options[:models] && Array(options[:models]) != [klass]) || Array(options[:index_name]).any? { |v| v.respond_to?(:searchkick_index) && v != klass } + raise ArgumentError, "Use Searchkick.search to search multiple models" end end diff --git a/lib/searchkick/index.rb b/lib/searchkick/index.rb index d7f51fb..c6f5721 100644 --- a/lib/searchkick/index.rb +++ b/lib/searchkick/index.rb @@ -17,7 +17,7 @@ module Searchkick end def delete - if !Searchkick.server_below?("6.0.0") && alias_exists? + if alias_exists? # can't call delete directly on aliases in ES 6 indices = client.indices.get_alias(name: name).keys client.indices.delete index: indices @@ -68,7 +68,7 @@ module Searchkick } ) - response["hits"]["total"] + Searchkick::Results.new(nil, response).total_count end def promote(new_name, update_refresh_interval: false) diff --git a/lib/searchkick/index_options.rb b/lib/searchkick/index_options.rb index e21f925..a89443c 100644 --- a/lib/searchkick/index_options.rb +++ b/lib/searchkick/index_options.rb @@ -4,15 +4,13 @@ module Searchkick options = @options language = options[:language] language = language.call if language.respond_to?(:call) - index_type = options[:_type] - index_type = index_type.call if index_type.respond_to?(:call) if options[:mappings] && !options[:merge_mappings] settings = options[:settings] || {} mappings = options[:mappings] else - below60 = Searchkick.server_below?("6.0.0") below62 = Searchkick.server_below?("6.2.0") + below70 = Searchkick.server_below?("7.0.0") default_type = "text" default_analyzer = :searchkick_index @@ -144,15 +142,6 @@ module Searchkick } } - if below60 - # ES docs say standard token filter does nothing in ES 5 - # (and therefore isn't needed at at), but tests say otherwise - # https://www.elastic.co/guide/en/elasticsearch/reference/5.0/analysis-standard-tokenfilter.html - [default_analyzer, :searchkick_search, :searchkick_search2].each do |analyzer| - settings[:analysis][:analyzer][analyzer][:filter].unshift("standard") - end - end - stem = options[:stem] case language @@ -279,8 +268,7 @@ module Searchkick # - Only apply the synonym expansion at index time # - Don't have the synonym filter applied search # - Use directional synonyms where appropriate. You want to make sure that you're not injecting terms that are too general. - settings[:analysis][:analyzer][default_analyzer][:filter].insert(4, "searchkick_synonym") if below60 - settings[:analysis][:analyzer][default_analyzer][:filter] << "searchkick_synonym" + settings[:analysis][:analyzer][default_analyzer][:filter].insert(2, "searchkick_synonym") %w(word_start word_middle word_end).each do |type| settings[:analysis][:analyzer]["searchkick_#{type}_index".to_sym][:filter].insert(2, "searchkick_synonym") @@ -391,10 +379,6 @@ module Searchkick "{name}" => keyword_mapping } - if below60 && all - dynamic_fields["{name}"][:include_in_all] = !options[:searchable] - end - if options.key?(:filterable) dynamic_fields["{name}"] = {type: default_type, index: index_false_value} end @@ -413,25 +397,24 @@ module Searchkick multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}")) mappings = { - index_type => { - properties: mapping, - _routing: routing, - # https://gist.github.com/kimchy/2898285 - dynamic_templates: [ - { - string_template: { - match: "*", - match_mapping_type: "string", - mapping: multi_field - } + properties: mapping, + _routing: routing, + # https://gist.github.com/kimchy/2898285 + dynamic_templates: [ + { + string_template: { + match: "*", + match_mapping_type: "string", + mapping: multi_field } - ] - } + } + ] } - if below60 - all_enabled = all && (!options[:searchable] || options[:searchable].to_a.map(&:to_s).include?("_all")) - mappings[index_type][:_all] = all_enabled ? analyzed_field_options : {enabled: false} + if below70 + index_type = options[:_type] + index_type = index_type.call if index_type.respond_to?(:call) + mappings = {index_type => mappings} end mappings = mappings.symbolize_keys.deep_merge((options[:mappings] || {}).symbolize_keys) diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index c637db0..b49e0d4 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -18,7 +18,7 @@ module Searchkick unknown_keywords = options.keys - [:aggs, :block, :body, :body_options, :boost, :boost_by, :boost_by_distance, :boost_by_recency, :boost_where, :conversions, :conversions_term, :debug, :emoji, :exclude, :execute, :explain, :fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load, - :match, :misspellings, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile, + :match, :misspellings, :models, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile, :request_params, :routing, :scope_results, :select, :similar, :smart_aggs, :suggest, :total_entries, :track, :type, :where] raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any? @@ -39,6 +39,7 @@ module Searchkick @misspellings = false @misspellings_below = nil @highlighted_fields = nil + @index_mapping = nil prepare end @@ -56,9 +57,18 @@ module Searchkick end def params + if options[:models] + @index_mapping = {} + Array(options[:models]).each do |model| + @index_mapping[model.searchkick_index.name] = model + end + end + index = if options[:index_name] Array(options[:index_name]).map { |v| v.respond_to?(:searchkick_index) ? v.searchkick_index.name : v }.join(",") + elsif options[:models] + @index_mapping.keys.join(",") elsif searchkick_index searchkick_index.name else @@ -116,8 +126,8 @@ module Searchkick misspellings: @misspellings, term: term, scope_results: options[:scope_results], - index_name: options[:index_name], - total_entries: options[:total_entries] + total_entries: options[:total_entries], + index_mapping: @index_mapping } if options[:debug] @@ -166,7 +176,7 @@ module Searchkick end def retry_misspellings?(response) - @misspellings_below && response["hits"]["total"] < @misspellings_below + @misspellings_below && Searchkick::Results.new(searchkick_klass, response).total_count < @misspellings_below end private @@ -377,7 +387,7 @@ module Searchkick queries_to_add.concat(q2) end - queries.concat(queries_to_add) + queries << queries_to_add if options[:exclude] must_not.concat(set_exclude(exclude_field, exclude_analyzer)) @@ -392,9 +402,10 @@ module Searchkick should = [] else + # higher score for matching more fields payload = { - dis_max: { - queries: queries + bool: { + should: queries.map { |qs| {dis_max: {queries: qs}} } } } @@ -663,20 +674,9 @@ module Searchkick def set_boost_by_indices(payload) return unless options[:indices_boost] - if below52? - indices_boost = options[:indices_boost].each_with_object({}) do |(key, boost), memo| - index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key - # try to use index explicitly instead of alias: https://github.com/elasticsearch/elasticsearch/issues/4756 - index_by_alias = Searchkick.client.indices.get_alias(index: index).keys.first - memo[index_by_alias || index] = boost - end - else - # array format supports alias resolution - # https://github.com/elastic/elasticsearch/pull/21393 - indices_boost = options[:indices_boost].map do |key, boost| - index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key - {index => boost} - end + indices_boost = options[:indices_boost].map do |key, boost| + index = key.respond_to?(:searchkick_index) ? key.searchkick_index.name : key + {index => boost} end payload[:indices_boost] = indices_boost @@ -713,7 +713,7 @@ module Searchkick def set_highlights(payload, fields) payload[:highlight] = { fields: Hash[fields.map { |f| [f, {}] }], - fragment_size: below60? ? 30000 : 0 + fragment_size: 0 } if options[:highlight].is_a?(Hash) @@ -824,7 +824,7 @@ module Searchkick # TODO id transformation for arrays def set_order(payload) order = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc} - id_field = below60? ? :_uid : :_id + id_field = :_id payload[:sort] = order.is_a?(Array) ? order : Hash[order.map { |k, v| [k.to_s == "id" ? id_field : k, v] }] end @@ -1021,16 +1021,12 @@ module Searchkick k.sub(/\.(analyzed|word_start|word_middle|word_end|text_start|text_middle|text_end|exact)\z/, "") end - def below52? - Searchkick.server_below?("5.2.0") - end - - def below60? - Searchkick.server_below?("6.0.0") - end - def below61? Searchkick.server_below?("6.1.0") end + + def below70? + Searchkick.server_below?("7.0.0") + end end end diff --git a/lib/searchkick/record_data.rb b/lib/searchkick/record_data.rb index 2381f52..ead2bde 100644 --- a/lib/searchkick/record_data.rb +++ b/lib/searchkick/record_data.rb @@ -34,18 +34,13 @@ module Searchkick index.klass_document_type(record.class, ignore_type) end - # memoize - def self.routing_key - @routing_key ||= Searchkick.server_below?("6.0.0") ? :_routing : :routing - end - def record_data data = { _index: index.name, - _id: search_id, - _type: document_type + _id: search_id } - data[self.class.routing_key] = record.search_routing if record.respond_to?(:search_routing) + data[:_type] = document_type if Searchkick.server_below7? + data[:routing] = record.search_routing if record.respond_to?(:search_routing) data end diff --git a/lib/searchkick/results.rb b/lib/searchkick/results.rb index c9e2b4c..acc5a9f 100644 --- a/lib/searchkick/results.rb +++ b/lib/searchkick/results.rb @@ -25,9 +25,16 @@ module Searchkick # results can have different types results = {} - hits.group_by { |hit, _| hit["_type"] }.each do |type, grouped_hits| - klass = (!options[:index_name] && @klass) || type.camelize.constantize - results[type] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s } + hits.group_by { |hit, _| hit["_index"] }.each do |index, grouped_hits| + klass = + if @klass + @klass + else + index_alias = index.split("_")[0..-2].join("_") + (options[:index_mapping] || {})[index_alias] + end + raise Searchkick::Error, "Unknown model for index: #{index}" unless klass + results[index] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s } end missing_ids = [] @@ -35,7 +42,7 @@ module Searchkick # sort results = hits.map do |hit| - result = results[hit["_type"]][hit["_id"].to_s] + result = results[hit["_index"]][hit["_id"].to_s] if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable]) if (hit["highlight"] || options[:highlight]) && !result.respond_to?(:search_highlights) highlights = hit_highlights(hit) @@ -132,7 +139,13 @@ module Searchkick end def total_count - options[:total_entries] || response["hits"]["total"] + if options[:total_entries] + options[:total_entries] + elsif response["hits"]["total"].is_a?(Hash) + response["hits"]["total"]["value"] + else + response["hits"]["total"] + end end alias_method :total_entries, :total_count diff --git a/searchkick.gemspec b/searchkick.gemspec index dec6ed4..e2bb4ec 100644 --- a/searchkick.gemspec +++ b/searchkick.gemspec @@ -16,10 +16,10 @@ Gem::Specification.new do |spec| spec.files = Dir["*.{md,txt}", "{lib}/**/*"] spec.require_path = "lib" - spec.required_ruby_version = ">= 2.2" + spec.required_ruby_version = ">= 2.4" - spec.add_dependency "activemodel", ">= 4.2" - spec.add_dependency "elasticsearch", ">= 5" + spec.add_dependency "activemodel", ">= 5" + spec.add_dependency "elasticsearch", ">= 6" spec.add_dependency "hashie" spec.add_development_dependency "bundler" diff --git a/test/aggs_test.rb b/test/aggs_test.rb index 4a24957..62c38f0 100644 --- a/test/aggs_test.rb +++ b/test/aggs_test.rb @@ -20,8 +20,7 @@ class AggsTest < Minitest::Test end def test_order - order_key = Searchkick.server_below?("6.0") ? "_term" : "_key" - agg = Product.search("Product", aggs: {color: {order: {order_key => "desc"}}}).aggs["color"] + agg = Product.search("Product", aggs: {color: {order: {_key: "desc"}}}).aggs["color"] assert_equal %w(red green blue), agg["buckets"].map { |b| b["key"] } end @@ -37,8 +36,7 @@ class AggsTest < Minitest::Test def test_script source = "'Color: ' + _value" - script = Searchkick.server_below?("5.6") ? {inline: source} : {source: source} - agg = Product.search("Product", aggs: {color: {script: script}}).aggs["color"] + agg = Product.search("Product", aggs: {color: {script: {source: source}}}).aggs["color"] assert_equal ({"Color: blue" => 1, "Color: green" => 1, "Color: red" => 1}), buckets_as_hash(agg) end diff --git a/test/boost_test.rb b/test/boost_test.rb index 5006d78..7aa5eab 100644 --- a/test/boost_test.rb +++ b/test/boost_test.rb @@ -67,6 +67,7 @@ class BoostTest < Minitest::Test end def test_conversions_weight + Product.reindex store [ {name: "Product Boost", orders_count: 20}, {name: "Product Conversions", conversions: {"product" => 10}} @@ -229,6 +230,6 @@ class BoostTest < Minitest::Test store_names ["Rex"], Animal store_names ["Rexx"], Product - assert_order "Rex", ["Rexx", "Rex"], {index_name: [Animal, Product], indices_boost: {Animal => 1, Product => 200}, fields: [:name]}, Store + assert_order "Rex", ["Rexx", "Rex"], {models: [Animal, Product], indices_boost: {Animal => 1, Product => 200}, fields: [:name]}, Searchkick end end diff --git a/test/ci/install_elasticsearch.sh b/test/ci/install_elasticsearch.sh index a662a78..d01198b 100755 --- a/test/ci/install_elasticsearch.sh +++ b/test/ci/install_elasticsearch.sh @@ -5,15 +5,13 @@ set -e CACHE_DIR=$HOME/elasticsearch/$ELASTICSEARCH_VERSION if [ ! -d "$CACHE_DIR" ]; then - if [[ $ELASTICSEARCH_VERSION == 1* ]]; then - URL=https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-$ELASTICSEARCH_VERSION.tar.gz - elif [[ $ELASTICSEARCH_VERSION == 2* ]]; then - URL=https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/$ELASTICSEARCH_VERSION/elasticsearch-$ELASTICSEARCH_VERSION.tar.gz + if [[ $ELASTICSEARCH_VERSION == 7* ]]; then + URL=https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-$ELASTICSEARCH_VERSION-linux-x86_64.tar.gz else URL=https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-$ELASTICSEARCH_VERSION.tar.gz fi - wget $URL + wget -O elasticsearch-$ELASTICSEARCH_VERSION.tar.gz $URL tar xvfz elasticsearch-$ELASTICSEARCH_VERSION.tar.gz mv elasticsearch-$ELASTICSEARCH_VERSION $CACHE_DIR else diff --git a/test/errors_test.rb b/test/errors_test.rb index 45a3f8a..bb08321 100644 --- a/test/errors_test.rb +++ b/test/errors_test.rb @@ -4,13 +4,15 @@ class ErrorsTest < Minitest::Test def test_bulk_import_raises_error valid_dog = Product.create(name: "2016-01-02") invalid_dog = Product.create(name: "Ol' One-Leg") - index = Searchkick::Index.new "dogs", mappings: { - dog: { - properties: { - name: {type: "date"} - } + mapping = { + properties: { + name: {type: "date"} } } + mapping = {product: mapping} if Searchkick.server_below?("7.0.0") + index = Searchkick::Index.new "dogs", mappings: mapping + index.delete if index.exists? + index.create_index index.store valid_dog assert_raises(Searchkick::ImportError) do index.bulk_index [valid_dog, invalid_dog] diff --git a/test/gemfiles/activerecord42.gemfile b/test/gemfiles/activerecord42.gemfile deleted file mode 100644 index 10777d3..0000000 --- a/test/gemfiles/activerecord42.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -source 'https://rubygems.org' - -# Specify your gem's dependencies in searchkick.gemspec -gemspec path: "../../" - -gem "sqlite3", "~> 1.3.0" -gem "activerecord", "~> 4.2.0" diff --git a/test/gemfiles/mongoid5.gemfile b/test/gemfiles/mongoid5.gemfile deleted file mode 100644 index 14bc005..0000000 --- a/test/gemfiles/mongoid5.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -source 'https://rubygems.org' - -# Specify your gem's dependencies in searchkick.gemspec -gemspec path: "../../" - -gem "mongoid", "~> 5.0.0" -gem "activejob" diff --git a/test/geo_shape_test.rb b/test/geo_shape_test.rb index 77fd681..33d6cea 100644 --- a/test/geo_shape_test.rb +++ b/test/geo_shape_test.rb @@ -32,6 +32,9 @@ class GeoShapeTest < Minitest::Test end def test_circle + # https://github.com/elastic/elasticsearch/issues/39237 + skip unless Searchkick.server_below?("6.6.0") + assert_search "*", ["Region A"], { where: { territory: { @@ -142,6 +145,9 @@ class GeoShapeTest < Minitest::Test end def test_contains + # CONTAINS query relation not supported + skip unless Searchkick.server_below?("6.6.0") + assert_search "*", ["Region C"], { where: { territory: { diff --git a/test/inheritance_test.rb b/test/inheritance_test.rb index e42a6f7..4289fbf 100644 --- a/test/inheritance_test.rb +++ b/test/inheritance_test.rb @@ -77,6 +77,20 @@ class InheritanceTest < Minitest::Test def test_multiple_indices store_names ["Product A"] store_names ["Product B"], Animal - assert_search "product", ["Product A", "Product B"], index_name: [Product.searchkick_index.name, Animal.searchkick_index.name], conversions: false + assert_search "product", ["Product A", "Product B"], {models: [Product, Animal], conversions: false}, Searchkick + assert_search "product", ["Product A", "Product B"], {index_name: [Product, Animal], conversions: false}, Searchkick + end + + def test_index_name_model + store_names ["Product A"] + assert_equal ["Product A"], Searchkick.search("product", index_name: [Product]).map(&:name) + end + + def test_index_name_string + store_names ["Product A"] + error = assert_raises Searchkick::Error do + Searchkick.search("product", index_name: [Product.searchkick_index.name]).map(&:name) + end + assert_includes error.message, "Unknown model" end end diff --git a/test/models/product.rb b/test/models/product.rb index 6e5ce3d..efd8c47 100644 --- a/test/models/product.rb +++ b/test/models/product.rb @@ -2,11 +2,8 @@ class Product searchkick \ synonyms: [ ["clorox", "bleach"], - ["scallion", "greenonion"], - ["saran wrap", "plastic wrap"], - ["qtip", "cottonswab"], ["burger", "hamburger"], - ["bandaid", "bandag"], + ["bandaid", "bandages"], ["UPPERCASE", "lowercase"], "lightbulb => led,lightbulb", "lightbulb => halogenlamp" diff --git a/test/models/region.rb b/test/models/region.rb index 2eaf426..3325e1b 100644 --- a/test/models/region.rb +++ b/test/models/region.rb @@ -1,8 +1,6 @@ class Region searchkick \ - geo_shape: { - territory: {tree: "quadtree", precision: "10km"} - } + geo_shape: [:territory] attr_accessor :territory diff --git a/test/models/store.rb b/test/models/store.rb index 01334a2..4102a96 100644 --- a/test/models/store.rb +++ b/test/models/store.rb @@ -1,14 +1,15 @@ class Store + mappings = { + properties: { + name: {type: "keyword"} + } + } + mappings = {store: mappings} if Searchkick.server_below?("7.0.0") + searchkick \ routing: true, merge_mappings: true, - mappings: { - store: { - properties: { - name: {type: "keyword"} - } - } - } + mappings: mappings def search_document_id id diff --git a/test/multi_indices_test.rb b/test/multi_indices_test.rb index 61bf51b..e5019df 100644 --- a/test/multi_indices_test.rb +++ b/test/multi_indices_test.rb @@ -7,16 +7,44 @@ class MultiIndicesTest < Minitest::Test assert_search_multi "product", ["Product A", "Product B"] end - def test_where - store [{name: "Product A", color: "red"}, {name: "Product B", color: "blue"}] - store_names ["Product C"], Speaker - assert_search_multi "product", ["Product A", "Product C"], where: {_or: [{_type: "product", color: "red"}, {_type: "speaker"}]} + def test_index_name + store_names ["Product A"] + assert_equal ["Product A"], Product.search("product", index_name: Product.searchkick_index.name).map(&:name) + assert_equal ["Product A"], Product.search("product", index_name: Product).map(&:name) + assert_equal [], Product.search("product", index_name: Speaker.searchkick_index.name, conversions: false).map(&:name) + end + + def test_models_and_index_name + store_names ["Product A"] + store_names ["Product B"], Speaker + assert_equal ["Product A"], Searchkick.search("product", models: [Product, Store], index_name: Product.searchkick_index.name).map(&:name) + error = assert_raises(Searchkick::Error) do + Searchkick.search("product", models: [Product, Store], index_name: Speaker.searchkick_index.name).map(&:name) + end + assert_includes error.message, "Unknown model" + # legacy + assert_equal ["Product A"], Searchkick.search("product", index_name: [Product, Store]).map(&:name) + end + + def test_model_with_another_model + error = assert_raises(ArgumentError) do + Product.search(models: [Store]) + end + assert_includes error.message, "Use Searchkick.search" + end + + def test_model_with_another_model_in_index_name + error = assert_raises(ArgumentError) do + # legacy protection + Product.search(index_name: [Store, "another"]) + end + assert_includes error.message, "Use Searchkick.search" end private def assert_search_multi(term, expected, options = {}) - options[:index_name] = [Product, Speaker] + options[:models] = [Product, Speaker] options[:fields] = [:name] assert_search(term, expected, options, Searchkick) end diff --git a/test/query_test.rb b/test/query_test.rb index 6e1088f..29d214c 100644 --- a/test/query_test.rb +++ b/test/query_test.rb @@ -4,18 +4,11 @@ class QueryTest < Minitest::Test def test_basic store_names ["Milk", "Apple"] query = Product.search("milk", execute: false) - # query.body = {query: {match_all: {}}} - # query.body = {query: {match: {name: "Apple"}}} query.body[:query] = {match_all: {}} assert_equal ["Apple", "Milk"], query.map(&:name).sort assert_equal ["Apple", "Milk"], query.execute.map(&:name).sort end - def test_with_effective_min_score - store_names ["Milk", "Milk2"] - assert_search "milk", ["Milk"], body_options: {min_score: 1} - end - def test_with_uneffective_min_score store_names ["Milk", "Milk2"] assert_search "milk", ["Milk", "Milk2"], body_options: {min_score: 0.0001} diff --git a/test/routing_test.rb b/test/routing_test.rb index ecbb589..f2ec672 100644 --- a/test/routing_test.rb +++ b/test/routing_test.rb @@ -7,8 +7,11 @@ class RoutingTest < Minitest::Test end def test_routing_mappings - index_options = Store.searchkick_index.index_options - assert_equal index_options[:mappings][:store][:_routing], required: true + mappings = Store.searchkick_index.index_options[:mappings] + if Searchkick.server_below?("7.0.0") + mappings = mappings[:store] + end + assert_equal mappings[:_routing], required: true end def test_routing_correct_node diff --git a/test/sql_test.rb b/test/sql_test.rb index fe46e0a..abd42db 100644 --- a/test/sql_test.rb +++ b/test/sql_test.rb @@ -37,6 +37,7 @@ class SqlTest < Minitest::Test end def test_fields_both_match + # have same score due to dismax store [ {name: "Blue A", color: "red"}, {name: "Blue B", color: "light blue"} @@ -172,7 +173,7 @@ class SqlTest < Minitest::Test store_names ["Store A"], Store associations = {Product => [:store], Store => [:products]} - result = Searchkick.search("*", index_name: [Product, Store], model_includes: associations) + result = Searchkick.search("*", models: [Product, Store], model_includes: associations) assert_equal 2, result.length diff --git a/test/suggest_test.rb b/test/suggest_test.rb index 1e92691..45fdadb 100644 --- a/test/suggest_test.rb +++ b/test/suggest_test.rb @@ -1,6 +1,11 @@ require_relative "test_helper" class SuggestTest < Minitest::Test + def setup + super + Product.reindex + end + def test_basic store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"] assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [:name] diff --git a/test/synonyms_test.rb b/test/synonyms_test.rb index 47de893..ce66356 100644 --- a/test/synonyms_test.rb +++ b/test/synonyms_test.rb @@ -6,11 +6,6 @@ class SynonymsTest < Minitest::Test assert_search "clorox", ["Clorox Bleach", "Kroger Bleach"] end - def test_saran_wrap - store_names ["Saran Wrap", "Kroger Plastic Wrap"] - assert_search "saran wrap", ["Saran Wrap", "Kroger Plastic Wrap"] - end - def test_burger_buns store_names ["Hamburger Buns"] assert_search "burger buns", ["Hamburger Buns"] @@ -21,24 +16,14 @@ class SynonymsTest < Minitest::Test assert_search "bandaids", ["Band-Aid", "Kroger 12-Pack Bandages"] end - def test_qtips - store_names ["Q Tips", "Kroger Cotton Swabs"] - assert_search "q tips", ["Q Tips", "Kroger Cotton Swabs"] - end - def test_reverse - store_names ["Scallions"] - assert_search "green onions", ["Scallions"] - end - - def test_exact - store_names ["Green Onions", "Yellow Onions"] - assert_search "scallion", ["Green Onions"] + store_names ["Hamburger"] + assert_search "burger", ["Hamburger"] end def test_stemmed - store_names ["Green Onions", "Yellow Onions"] - assert_search "scallions", ["Green Onions"] + store_names ["Burger"] + assert_search "hamburgers", ["Burger"] end def test_word_start -- libgit2 0.21.0