Permalink
Browse files

Merge commit '1fb35cc0f183480e018daa8a5da6b163f22732bd' into handle_h…

…ashie

* commit '1fb35cc0f183480e018daa8a5da6b163f22732bd': (27 commits)
  Use better ActiveRecord hook - fixes ankane#910
  Removed unnecessary option [skip ci]
  Updated readme
  resolve customizable queue name as requested in ankane#799 (ankane#909)
  Updated tests to ES 5.3.2
  fix bulk index without IDs ankane#907 (ankane#908)
  Updated tests to ActiveRecord 5.1
  Version bump to 2.2.1
  Added index_suffix option - ankane#891
  Added load: {dumpable: true} option - closes ankane#887
  Test on Elasticsearch 5.3
  Updated changelog [skip ci]
  Support avg, cardinality, min, max and sum metric aggregates (ankane#877)
  Support cardinality metric aggregator (ankane#876)
  Improved exclude example [skip ci]
  Accept string for exclude option
  Improved synonyms section [skip ci]
  Added test for OR operator scoring
  Version bump to 2.2.0
  Fixed exclude case for exact match
  ...
  • Loading branch information...
mikelkew committed May 1, 2017
2 parents 2ec2660 + 1fb35cc commit 81e8623a6fb79edb44da15265acf9f0088d05cc3
View
@@ -6,7 +6,7 @@ services:
- redis-server
before_install:
- ./test/ci/before_install.sh
script: RUBYOPT=W0 bundle exec rake test
script: bundle exec rake test
before_script:
- psql -c 'create database searchkick_test;' -U postgres
notifications:
@@ -15,11 +15,12 @@ notifications:
on_failure: change
gemfile:
- Gemfile
- test/gemfiles/activerecord50.gemfile
- test/gemfiles/activerecord42.gemfile
- test/gemfiles/mongoid5.gemfile
- test/gemfiles/mongoid6.gemfile
env:
- ELASTICSEARCH_VERSION=5.2.0
- ELASTICSEARCH_VERSION=5.3.2
jdk: oraclejdk8
matrix:
include:
View
@@ -1,6 +1,19 @@
## 2.1.2 [unreleased]
## 2.2.2 [unreleased]
- Added `queue_name` option
## 2.2.1
- Added `avg`, `cardinality`, `max`, `min`, and `sum` aggregations
- Added `load: {dumpable: true}` option
- Added `index_suffix` option
- Accept string for `exclude` option
## 2.2.0
- Fixed bug with text values longer than 256 characters and `_all` field - see [#850](https://github.com/ankane/searchkick/issues/850)
- Fixed issue with `_all` field in `searchable`
- Fixed `exclude` option with `word_start`
## 2.1.1
View
@@ -4,7 +4,7 @@ source "https://rubygems.org"
gemspec
gem "sqlite3"
gem "activerecord", "~> 5.0.0"
gem "activerecord", "~> 5.1.0"
gem "gemoji-parser"
gem "typhoeus"
gem "activejob"
View
@@ -294,13 +294,17 @@ end
```ruby
class Product < ActiveRecord::Base
searchkick synonyms: [["scallion", "green onion"], ["qtip", "cotton swab"]]
# or
# searchkick synonyms: -> { CSV.read("/some/path/synonyms.csv") }
end
```
Call `Product.reindex` after changing synonyms.
To read synonyms from a file, use:
```ruby
synonyms: -> { CSV.read("/some/path/synonyms.csv") }
```
For directional synonyms, use:
```ruby
@@ -388,7 +392,7 @@ You can map queries and terms to exclude with:
```ruby
exclude_queries = {
"butter" => ["peanut butter"],
"cream" => ["ice cream"]
"cream" => ["ice cream", "whipped cream"]
}
Product.search query, exclude: exclude_queries[query]
@@ -1027,7 +1031,7 @@ Product.search_index.tokens("dieg", analyzer: "searchkick_word_search")
# ["dieg"] - match!!
```
See the [complete list of analyzers](lib/searchkick/index.rb#L209).
See the [complete list of analyzers](https://github.com/ankane/searchkick/blob/31780ddac7a89eab1e0552a32b403f2040a37931/lib/searchkick/index_options.rb#L32).
## Deployment
@@ -1602,12 +1606,18 @@ Set a lower timeout for searches
Searchkick.search_timeout = 3
```
Change the search method name in `config/initializers/searchkick.rb`
Change the search method name
```ruby
Searchkick.search_method_name = :lookup
```
Change search queue name [master]
```ruby
Searchkick.queue_name = :search_reindex
```
Eager load associations
```ruby
@@ -1689,26 +1699,91 @@ Product.search "ah", misspellings: {prefix_length: 2} # ah, no aha
## Testing
This section could use some love.
For performance, only enable Searchkick callbacks for the tests that need it.
### Minitest
Add to your `test/test_helper.rb`:
```ruby
# reindex models
Product.reindex
# and disable callbacks
Searchkick.disable_callbacks
```
And use:
```ruby
class ProductTest < Minitest::Test
def setup
Searchkick.enable_callbacks
end
def teardown
Searchkick.disable_callbacks
end
def test_search
Product.create!(name: "Apple")
Product.search_index.refresh
assert_equal ["Apple"], Product.search("apple").map(&:name)
end
end
```
### RSpec
Add to your `spec/spec_helper.rb`:
```ruby
describe Product do
it "searches" do
RSpec.configure do |config|
config.before(:suite) do
# reindex models
Product.reindex
# test goes here...
# and disable callbacks
Searchkick.disable_callbacks
end
config.around(:each, search: true) do |example|
Searchkick.enable_callbacks
example.run
Searchkick.disable_callbacks
end
end
```
And use:
```ruby
describe Product, search: true do
it "searches" do
Product.create!(name: "Apple")
Product.search_index.refresh
assert_equal ["Apple"], Product.search("apple").map(&:name)
end
end
```
### Factory Girl
Manually reindex after an instance is created.
```ruby
product = FactoryGirl.create(:product)
product.reindex(refresh: true)
```
### Parallel Tests
Set:
```ruby
Searchkick.index_suffix = ENV["TEST_ENV_NUMBER"]
```
## Multi-Tenancy
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.
View
@@ -1,6 +1,13 @@
require "bundler/gem_tasks"
require "rake/testtask"
begin
require "parallel_tests/tasks"
require "shellwords"
rescue LoadError
# do nothing
end
task default: :test
Rake::TestTask.new do |t|
t.libs << "test"
View
@@ -37,7 +37,7 @@ class DangerousOperation < Error; end
class ImportError < Error; end
class << self
attr_accessor :search_method_name, :wordnet_path, :timeout, :models, :client_options, :redis
attr_accessor :search_method_name, :wordnet_path, :timeout, :models, :client_options, :redis, :index_suffix, :queue_name
attr_writer :client, :env, :search_timeout
attr_reader :aws_credentials
end
@@ -46,6 +46,7 @@ class << self
self.timeout = 10
self.models = []
self.client_options = {}
self.queue_name = :searchkick
def self.client
@client ||= begin
@@ -207,4 +208,7 @@ def self.callbacks_value=(value)
# TODO find better ActiveModel hook
ActiveModel::Callbacks.send(:include, Searchkick::Model)
ActiveRecord::Base.send(:extend, Searchkick::Model) if defined?(ActiveRecord)
ActiveSupport.on_load(:active_record) do
extend Searchkick::Model
end
@@ -25,7 +25,7 @@ def index_options
}
end
keyword_mapping[:ignore_above] = (options[:ignore_above] || 256) unless below22
keyword_mapping[:ignore_above] = (options[:ignore_above] || 30000) unless below22
settings = {
analysis: {
View
@@ -21,8 +21,8 @@ def searchkick(**options)
class_variable_set :@@searchkick_klass, self
class_variable_set :@@searchkick_callbacks, callbacks
class_variable_set :@@searchkick_index, options[:index_name] ||
(options[:index_prefix].respond_to?(:call) && proc { [options[:index_prefix].call, model_name.plural, Searchkick.env].compact.join("_") }) ||
[options[:index_prefix], model_name.plural, Searchkick.env].compact.join("_")
(options[:index_prefix].respond_to?(:call) && proc { [options[:index_prefix].call, model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_") }) ||
[options[:index_prefix], model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_")
class << self
def searchkick_search(term = "*", **options, &block)
View
@@ -2,6 +2,8 @@ module Searchkick
class Query
extend Forwardable
@@metric_aggs = [:avg, :cardinality, :max, :min, :sum]
attr_reader :klass, :term, :options
attr_accessor :body
@@ -283,18 +285,25 @@ def prepare
shared_options[:operator] = operator if match_type == :match
exclude_analyzer = nil
exclude_field = field
if field == "_all" || field.end_with?(".analyzed")
shared_options[:cutoff_frequency] = 0.001 unless operator == "and" || misspellings == false
qs.concat [
shared_options.merge(analyzer: "searchkick_search"),
shared_options.merge(analyzer: "searchkick_search2")
]
exclude_analyzer = "searchkick_search2"
elsif field.end_with?(".exact")
f = field.split(".")[0..-2].join(".")
queries_to_add << {match: {f => shared_options.merge(analyzer: "keyword")}}
exclude_field = f
exclude_analyzer = "keyword"
else
analyzer = field =~ /\.word_(start|middle|end)\z/ ? "searchkick_word_search" : "searchkick_autocomplete_search"
qs << shared_options.merge(analyzer: analyzer)
exclude_analyzer = analyzer
end
if misspellings != false && match_type == :match
@@ -321,10 +330,13 @@ def prepare
if options[:exclude]
must_not =
options[:exclude].map do |phrase|
Array(options[:exclude]).map do |phrase|
{
match_phrase: {
field => phrase
exclude_field => {
query: phrase,
analyzer: exclude_analyzer
}
}
}
end
@@ -633,6 +645,12 @@ def set_aggregations(payload)
interval: interval
}
}
elsif metric = @@metric_aggs.find { |k| agg_options.has_key?(k) }
payload[:aggs][field] = {
metric => {
field: agg_options[metric][:field] || field
}
}
else
payload[:aggs][field] = {
terms: {
@@ -7,7 +7,7 @@ class ReindexV2Job < ActiveJob::Base
"Cequel::Record::RecordNotFound"
]
queue_as :searchkick
queue_as { Searchkick.queue_name }
def perform(klass, id)
model = klass.constantize
@@ -33,7 +33,7 @@ def results
# sort
hits.map do |hit|
result = results[hit["_type"]][hit["_id"].to_s]
if result
if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])
unless result.respond_to?(:search_hit)
result.define_singleton_method(:search_hit) do
hit
@@ -1,3 +1,3 @@
module Searchkick
VERSION = "2.1.1"
VERSION = "2.2.1"
end
Oops, something went wrong.

0 comments on commit 81e8623

Please sign in to comment.