elasticsearch_autocomplete 0.1.2 → 0.1.3
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 +7 -0
- data/.travis.yml +15 -0
- data/README.md +6 -0
- data/elasticsearch_autocomplete.gemspec +1 -1
- data/lib/elasticsearch_autocomplete.rb +3 -2
- data/lib/elasticsearch_autocomplete/model_addition.rb +3 -3
- data/lib/elasticsearch_autocomplete/railtie.rb +6 -0
- data/lib/elasticsearch_autocomplete/version.rb +1 -1
- data/spec/elasticsearch_autocomplete/base_spec.rb +36 -0
- data/spec/elasticsearch_autocomplete/full_mode_spec.rb +8 -9
- data/spec/elasticsearch_autocomplete/localized_spec.rb +5 -6
- data/spec/elasticsearch_autocomplete/phrase_mode_spec.rb +5 -4
- data/spec/elasticsearch_autocomplete/search_filters_spec.rb +9 -10
- data/spec/elasticsearch_autocomplete/word_mode_spec.rb +6 -7
- data/spec/spec_helper.rb +1 -1
- metadata +29 -44
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ec053155e8286256103931b33b97f4bae9108f0f
|
4
|
+
data.tar.gz: 3f2f2be1ab323398e21dbe1feb543313b5903cc7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b5a457a872f4bd0540fa8f26ffc87faa72744a8dbc67a28d020b7f7f05403d2640f40e61578fcd9da38e29a31caf259b7a4d33ccba41e8b032b6d50ce45e08bc
|
7
|
+
data.tar.gz: 4bbf9a2a52d161b122323f5c0b08c7b98989406babde58749f1cfaff72b1297d1d38fe5734e7a1576727dc1a967cb4f3200b3c88ae45c30ae7f674763b695852
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
Simple autocomplete for rails models using awesome [Elasticsearch](http://www.elasticsearch.org/) and [tire](https://github.com/karmi/tire) gem
|
4
4
|
|
5
|
+
[](https://travis-ci.org/leschenko/elasticsearch_autocomplete)
|
6
|
+
|
7
|
+
## Example app
|
8
|
+
|
9
|
+
Look at ElasticsearchAutocomplete [example app](https://github.com/leschenko/example_elasticsearch_autocomplete)
|
10
|
+
|
5
11
|
## Installation
|
6
12
|
|
7
13
|
Add this line to your application's Gemfile:
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = %w(lib)
|
19
19
|
|
20
|
-
gem.add_dependency 'tire'
|
20
|
+
gem.add_dependency 'tire', '~> 0.6.0'
|
21
21
|
|
22
22
|
gem.add_development_dependency 'rake'
|
23
23
|
gem.add_development_dependency 'rspec'
|
@@ -1,13 +1,14 @@
|
|
1
|
+
require 'tire'
|
1
2
|
require 'elasticsearch_autocomplete/version'
|
2
3
|
require 'elasticsearch_autocomplete/analyzers'
|
3
4
|
require 'elasticsearch_autocomplete/model_addition'
|
4
|
-
require 'elasticsearch_autocomplete/railtie' if
|
5
|
+
require 'elasticsearch_autocomplete/railtie' if Object.const_defined?(:Rails)
|
5
6
|
|
6
7
|
module ElasticsearchAutocomplete
|
7
8
|
mattr_accessor :defaults
|
8
9
|
|
9
10
|
def self.default_index_prefix
|
10
|
-
Rails.application.class.name.split('::').first.downcase
|
11
|
+
Object.const_defined?(:Rails) ? ::Rails.application.class.name.split('::').first.downcase : nil
|
11
12
|
end
|
12
13
|
|
13
14
|
self.defaults = {:attr => :name, :localized => false, :mode => :word, :index_prefix => default_index_prefix}
|
@@ -11,7 +11,7 @@ module ElasticsearchAutocomplete
|
|
11
11
|
after_save lambda { tire.update_index }
|
12
12
|
end
|
13
13
|
after_destroy lambda { tire.update_index }
|
14
|
-
index_prefix ElasticsearchAutocomplete.defaults[:index_prefix]
|
14
|
+
index_prefix ElasticsearchAutocomplete.defaults[:index_prefix] if ElasticsearchAutocomplete.defaults[:index_prefix]
|
15
15
|
end
|
16
16
|
|
17
17
|
def ac_field(*args, &block)
|
@@ -38,9 +38,9 @@ module ElasticsearchAutocomplete
|
|
38
38
|
|
39
39
|
module ClassMethods
|
40
40
|
def ac_search(query, options={})
|
41
|
-
options.reverse_merge!({:per_page => 50, :search_fields => ac_search_fields})
|
41
|
+
options.reverse_merge!({:per_page => 50, :search_fields => ac_search_fields, :load => false})
|
42
42
|
|
43
|
-
tire.search :per_page => options[:per_page], :page => options[:page] do
|
43
|
+
tire.search :per_page => options[:per_page], :page => options[:page], :load => options[:load] do
|
44
44
|
query do
|
45
45
|
if query.size.zero?
|
46
46
|
all
|
@@ -1,9 +1,15 @@
|
|
1
1
|
module ElasticsearchAutocomplete
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
initializer 'elasticsearch_autocomplete.model_additions' do
|
4
|
+
|
5
|
+
ActiveSupport.on_load :mongoid do
|
6
|
+
const_get(:ClassMethods).send :include, ElasticsearchAutocomplete::ModelAddition::SingletonMethods
|
7
|
+
end
|
8
|
+
|
4
9
|
ActiveSupport.on_load :active_record do
|
5
10
|
include ElasticsearchAutocomplete::ModelAddition
|
6
11
|
end
|
12
|
+
|
7
13
|
end
|
8
14
|
end
|
9
15
|
end
|
@@ -2,6 +2,28 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
class ActiveModelUser < StubModelBase
|
4
4
|
ac_field :full_name
|
5
|
+
|
6
|
+
def self.test_data
|
7
|
+
['Test User', 'Test User2']
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.populate
|
11
|
+
test_data.each_with_index do |name, id|
|
12
|
+
u = new(:full_name => name)
|
13
|
+
u.id = id
|
14
|
+
u.save
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Stub for find, which takes in array of ids.
|
19
|
+
def self.find(ids)
|
20
|
+
ids.map do |id|
|
21
|
+
id = id.to_i
|
22
|
+
u = new(:full_name => test_data[id])
|
23
|
+
u.id = id
|
24
|
+
u
|
25
|
+
end
|
26
|
+
end
|
5
27
|
end
|
6
28
|
|
7
29
|
describe ElasticsearchAutocomplete do
|
@@ -30,6 +52,20 @@ describe ElasticsearchAutocomplete do
|
|
30
52
|
ElasticsearchAutocomplete.defaults.should == {:attr => :test, :localized => true, :mode => :phrase, :index_prefix => 'test'}
|
31
53
|
end
|
32
54
|
end
|
55
|
+
|
56
|
+
describe 'eager loading' do
|
57
|
+
it 'does not eager load the records from ac_search by default' do
|
58
|
+
results = ActiveModelUser.ac_search('Test User')
|
59
|
+
results.to_a.should_not be_empty
|
60
|
+
results.map{|x| x.is_a?(ActiveModelUser).should == false }
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'eager loads the records from ac_search' do
|
64
|
+
results = ActiveModelUser.ac_search('Test User', :load => true)
|
65
|
+
results.to_a.should_not be_empty
|
66
|
+
results.map{|x| x.is_a?(ActiveModelUser).should == true }
|
67
|
+
end
|
68
|
+
end
|
33
69
|
end
|
34
70
|
|
35
71
|
shared_examples 'basic autocomplete' do |model|
|
@@ -17,33 +17,32 @@ class ActiveModelProductFull < StubModelBase
|
|
17
17
|
end
|
18
18
|
|
19
19
|
describe ':full mode autocomplete' do
|
20
|
-
let(:model) { ActiveModelProductFull }
|
21
|
-
|
22
20
|
before :all do
|
23
|
-
model
|
21
|
+
@model = ActiveModelProductFull
|
22
|
+
@model.setup_index
|
24
23
|
end
|
25
24
|
|
26
25
|
it 'have :full mode' do
|
27
|
-
model.ac_opts[:mode].should == :full
|
26
|
+
@model.ac_opts[:mode].should == :full
|
28
27
|
end
|
29
28
|
|
30
29
|
it 'suggest for beginning of the source' do
|
31
|
-
model.ac_search('A.31').to_a.should_not be_empty
|
30
|
+
@model.ac_search('A.31').to_a.should_not be_empty
|
32
31
|
end
|
33
32
|
|
34
33
|
it 'suggest for for full match' do
|
35
|
-
model.ac_search('SAMARA').to_a.should_not be_empty
|
34
|
+
@model.ac_search('SAMARA').to_a.should_not be_empty
|
36
35
|
end
|
37
36
|
|
38
37
|
it 'don\'t suggest for unmatched term' do
|
39
|
-
model.ac_search('kac3').to_a.should be_empty
|
38
|
+
@model.ac_search('kac3').to_a.should be_empty
|
40
39
|
end
|
41
40
|
|
42
41
|
it 'suggest from the middle of the word' do
|
43
|
-
model.ac_search('/sm').to_a.should_not be_empty
|
42
|
+
@model.ac_search('/sm').to_a.should_not be_empty
|
44
43
|
end
|
45
44
|
|
46
45
|
it 'suggest with relevance order' do
|
47
|
-
model.ac_search('A.3').map(&:sku).should == ['A.3103', 'b A.3611']
|
46
|
+
@model.ac_search('A.3').map(&:sku).should == ['A.3103', 'b A.3611']
|
48
47
|
end
|
49
48
|
end
|
@@ -20,15 +20,14 @@ class ActiveModelProductLocalized < StubModelBase
|
|
20
20
|
end
|
21
21
|
|
22
22
|
describe 'suggestions for localized attributes' do
|
23
|
-
let(:model) { ActiveModelProductLocalized }
|
24
|
-
|
25
23
|
before :all do
|
26
|
-
model
|
24
|
+
@model = ActiveModelProductLocalized
|
25
|
+
@model.setup_index
|
27
26
|
end
|
28
27
|
|
29
28
|
it 'don\'t suggest from all locales' do
|
30
|
-
model.ac_search('name_en first').to_a.should have(1).results
|
31
|
-
model.ac_search('name_ru first').to_a.should have(1).results
|
32
|
-
model.ac_search('name_ru').to_a.should have(2).results
|
29
|
+
@model.ac_search('name_en first').to_a.should have(1).results
|
30
|
+
@model.ac_search('name_ru first').to_a.should have(1).results
|
31
|
+
@model.ac_search('name_ru').to_a.should have(2).results
|
33
32
|
end
|
34
33
|
end
|
@@ -7,20 +7,21 @@ end
|
|
7
7
|
describe ':phrase mode autocomplete' do
|
8
8
|
let(:model) { ActiveModelUserPhrase }
|
9
9
|
before :all do
|
10
|
-
model
|
10
|
+
@model = ActiveModelUserPhrase
|
11
|
+
@model.setup_index
|
11
12
|
end
|
12
13
|
|
13
14
|
it 'have :phrase mode' do
|
14
|
-
model.ac_opts[:mode].should == :phrase
|
15
|
+
@model.ac_opts[:mode].should == :phrase
|
15
16
|
end
|
16
17
|
|
17
18
|
it_behaves_like 'basic autocomplete', ActiveModelUserPhrase
|
18
19
|
|
19
20
|
it 'don\'t suggest from the middle of the word' do
|
20
|
-
model.ac_search('becca').to_a.should be_empty
|
21
|
+
@model.ac_search('becca').to_a.should be_empty
|
21
22
|
end
|
22
23
|
|
23
24
|
it 'don\'t for each word of the source' do
|
24
|
-
model.ac_search('Flores').map(&:full_name).should be_empty
|
25
|
+
@model.ac_search('Flores').map(&:full_name).should be_empty
|
25
26
|
end
|
26
27
|
end
|
@@ -30,40 +30,39 @@ class ActiveModelUserFilter < StubModelBase
|
|
30
30
|
end
|
31
31
|
|
32
32
|
describe 'search filters' do
|
33
|
-
let(:model) { ActiveModelUserFilter }
|
34
|
-
|
35
33
|
before :all do
|
36
|
-
model
|
34
|
+
@model = ActiveModelUserFilter
|
35
|
+
@model.setup_index
|
37
36
|
end
|
38
37
|
|
39
38
|
it 'filter suggestions with terms' do
|
40
|
-
model.ac_search('Laura', :with => {:interest_ids => [2]}).map(&:full_name).should =~ ['Laura Nelson', 'Laura Flores']
|
39
|
+
@model.ac_search('Laura', :with => {:interest_ids => [2]}).map(&:full_name).should =~ ['Laura Nelson', 'Laura Flores']
|
41
40
|
end
|
42
41
|
|
43
42
|
it 'accept coma separated string for filter' do
|
44
|
-
model.ac_search('Laura', :with => {:interest_ids => '1,4'}).map(&:full_name).should =~ ['Laura Nelson', 'Laura Larson']
|
43
|
+
@model.ac_search('Laura', :with => {:interest_ids => '1,4'}).map(&:full_name).should =~ ['Laura Nelson', 'Laura Larson']
|
45
44
|
end
|
46
45
|
|
47
46
|
it 'filter suggestions without terms' do
|
48
|
-
model.ac_search('Laura', :without => {:interest_ids => [2]}).map(&:full_name).should =~ ['Laura Larson']
|
47
|
+
@model.ac_search('Laura', :without => {:interest_ids => [2]}).map(&:full_name).should =~ ['Laura Larson']
|
49
48
|
end
|
50
49
|
|
51
50
|
it 'can order suggestions desc' do
|
52
|
-
res = model.ac_search('Laura', :order => :id, :sort_mode => 'desc').map(&:id)
|
51
|
+
res = @model.ac_search('Laura', :order => :id, :sort_mode => 'desc').map(&:id)
|
53
52
|
res.should == res.sort.reverse
|
54
53
|
end
|
55
54
|
|
56
55
|
it 'can order suggestions asc' do
|
57
|
-
res = model.ac_search('Laura', :order => :id, :sort_mode => 'asc').map(&:id)
|
56
|
+
res = @model.ac_search('Laura', :order => :id, :sort_mode => 'asc').map(&:id)
|
58
57
|
res.should == res.sort
|
59
58
|
end
|
60
59
|
|
61
60
|
it 'limit suggestions collection size' do
|
62
|
-
model.ac_search('Laura', :per_page => 1).to_a.should have(1).result
|
61
|
+
@model.ac_search('Laura', :per_page => 1).to_a.should have(1).result
|
63
62
|
end
|
64
63
|
|
65
64
|
it 'paginate suggestions' do
|
66
|
-
res = model.ac_search('Laura', :per_page => 1, :page => 2).to_a
|
65
|
+
res = @model.ac_search('Laura', :per_page => 1, :page => 2).to_a
|
67
66
|
res.should have(1).result
|
68
67
|
res.first.full_name.should == 'Laura Flores'
|
69
68
|
end
|
@@ -5,27 +5,26 @@ class ActiveModelUserWord < StubModelBase
|
|
5
5
|
end
|
6
6
|
|
7
7
|
describe ':word mode autocomplete' do
|
8
|
-
let(:model) { ActiveModelUserWord }
|
9
|
-
|
10
8
|
before :all do
|
11
|
-
model
|
9
|
+
@model = ActiveModelUserWord
|
10
|
+
@model.setup_index
|
12
11
|
end
|
13
12
|
|
14
13
|
it 'have :word mode' do
|
15
|
-
model.ac_opts[:mode].should == :word
|
14
|
+
@model.ac_opts[:mode].should == :word
|
16
15
|
end
|
17
16
|
|
18
17
|
it_behaves_like 'basic autocomplete', ActiveModelUserWord
|
19
18
|
|
20
19
|
it 'don\'t suggest from the middle of the word' do
|
21
|
-
model.ac_search('becca').to_a.should be_empty
|
20
|
+
@model.ac_search('becca').to_a.should be_empty
|
22
21
|
end
|
23
22
|
|
24
23
|
it 'suggest for each word of the source' do
|
25
|
-
model.ac_search('Flores').map(&:full_name).should == ['Joyce Flores']
|
24
|
+
@model.ac_search('Flores').map(&:full_name).should == ['Joyce Flores']
|
26
25
|
end
|
27
26
|
|
28
27
|
it 'suggest with relevance order' do
|
29
|
-
model.ac_search('Lau').map(&:full_name).should == ['Laura Larson', 'Larson Laura']
|
28
|
+
@model.ac_search('Lau').map(&:full_name).should == ['Laura Larson', 'Larson Laura']
|
30
29
|
end
|
31
30
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,7 +4,7 @@ require 'active_support/core_ext'
|
|
4
4
|
require 'elasticsearch_autocomplete'
|
5
5
|
|
6
6
|
Tire.configure do
|
7
|
-
logger 'tmp/elasticsearch.log'
|
7
|
+
#logger 'tmp/elasticsearch.log' # Commented out logger line here so that it doesn't break specs when tmp directory doesn't exist.
|
8
8
|
url 'http://localhost:9200'
|
9
9
|
pretty 1
|
10
10
|
end
|
metadata
CHANGED
@@ -1,80 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticsearch_autocomplete
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.1.2
|
4
|
+
version: 0.1.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Alex Leschenko
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-06-19 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
version_requirements: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ! '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
none: false
|
21
|
-
prerelease: false
|
22
14
|
name: tire
|
23
15
|
requirement: !ruby/object:Gem::Requirement
|
24
16
|
requirements:
|
25
|
-
- -
|
17
|
+
- - ~>
|
26
18
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
28
|
-
none: false
|
19
|
+
version: 0.6.0
|
29
20
|
type: :runtime
|
30
|
-
|
21
|
+
prerelease: false
|
31
22
|
version_requirements: !ruby/object:Gem::Requirement
|
32
23
|
requirements:
|
33
|
-
- -
|
24
|
+
- - ~>
|
34
25
|
- !ruby/object:Gem::Version
|
35
|
-
version:
|
36
|
-
|
37
|
-
prerelease: false
|
26
|
+
version: 0.6.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
38
28
|
name: rake
|
39
29
|
requirement: !ruby/object:Gem::Requirement
|
40
30
|
requirements:
|
41
|
-
- -
|
31
|
+
- - '>='
|
42
32
|
- !ruby/object:Gem::Version
|
43
33
|
version: '0'
|
44
|
-
none: false
|
45
34
|
type: :development
|
46
|
-
|
35
|
+
prerelease: false
|
47
36
|
version_requirements: !ruby/object:Gem::Requirement
|
48
37
|
requirements:
|
49
|
-
- -
|
38
|
+
- - '>='
|
50
39
|
- !ruby/object:Gem::Version
|
51
40
|
version: '0'
|
52
|
-
|
53
|
-
prerelease: false
|
41
|
+
- !ruby/object:Gem::Dependency
|
54
42
|
name: rspec
|
55
43
|
requirement: !ruby/object:Gem::Requirement
|
56
44
|
requirements:
|
57
|
-
- -
|
45
|
+
- - '>='
|
58
46
|
- !ruby/object:Gem::Version
|
59
47
|
version: '0'
|
60
|
-
none: false
|
61
48
|
type: :development
|
62
|
-
|
49
|
+
prerelease: false
|
63
50
|
version_requirements: !ruby/object:Gem::Requirement
|
64
51
|
requirements:
|
65
|
-
- -
|
52
|
+
- - '>='
|
66
53
|
- !ruby/object:Gem::Version
|
67
54
|
version: '0'
|
68
|
-
|
69
|
-
prerelease: false
|
55
|
+
- !ruby/object:Gem::Dependency
|
70
56
|
name: oj
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
|
-
- -
|
59
|
+
- - '>='
|
74
60
|
- !ruby/object:Gem::Version
|
75
61
|
version: '0'
|
76
|
-
none: false
|
77
62
|
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
78
69
|
description: Simple autocomplete for your models using awesome elasticsearch and tire
|
79
70
|
gem
|
80
71
|
email:
|
@@ -84,6 +75,7 @@ extensions: []
|
|
84
75
|
extra_rdoc_files: []
|
85
76
|
files:
|
86
77
|
- .gitignore
|
78
|
+
- .travis.yml
|
87
79
|
- Gemfile
|
88
80
|
- LICENSE.txt
|
89
81
|
- README.md
|
@@ -103,33 +95,26 @@ files:
|
|
103
95
|
- spec/spec_helper.rb
|
104
96
|
homepage: https://github.com/leschenko/elasticsearch_autocomplete
|
105
97
|
licenses: []
|
98
|
+
metadata: {}
|
106
99
|
post_install_message:
|
107
100
|
rdoc_options: []
|
108
101
|
require_paths:
|
109
102
|
- lib
|
110
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|
111
104
|
requirements:
|
112
|
-
- -
|
105
|
+
- - '>='
|
113
106
|
- !ruby/object:Gem::Version
|
114
107
|
version: '0'
|
115
|
-
segments:
|
116
|
-
- 0
|
117
|
-
hash: 4258391315820171784
|
118
|
-
none: false
|
119
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
109
|
requirements:
|
121
|
-
- -
|
110
|
+
- - '>='
|
122
111
|
- !ruby/object:Gem::Version
|
123
112
|
version: '0'
|
124
|
-
segments:
|
125
|
-
- 0
|
126
|
-
hash: 4258391315820171784
|
127
|
-
none: false
|
128
113
|
requirements: []
|
129
114
|
rubyforge_project:
|
130
|
-
rubygems_version:
|
115
|
+
rubygems_version: 2.0.3
|
131
116
|
signing_key:
|
132
|
-
specification_version:
|
117
|
+
specification_version: 4
|
133
118
|
summary: Elasticsearch autocomplete for models
|
134
119
|
test_files:
|
135
120
|
- spec/elasticsearch_autocomplete/base_spec.rb
|