activesearch 0.0.3 → 0.0.4
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.
- data/README.md +26 -23
- data/activesearch.gemspec +5 -2
- data/elasticsearch.log +24 -0
- data/lib/activesearch/elastic_search/proxy.rb +26 -0
- data/lib/activesearch/elastic_search.rb +30 -0
- data/lib/activesearch/mongoid/model.rb +19 -10
- data/lib/activesearch/mongoid.rb +24 -11
- data/lib/activesearch/result.rb +13 -0
- data/lib/activesearch/version.rb +1 -1
- data/lib/activesearch.rb +1 -1
- data/log/elasticsearch.log +93792 -0
- data/spec/engines_spec.rb +54 -0
- data/spec/models/elastic_search.rb +35 -0
- data/spec/models/mongoid.rb +31 -0
- data/spec/mongoid_spec.rb +7 -45
- data/spec/spec_helper.rb +31 -0
- metadata +65 -4
data/README.md
CHANGED
@@ -4,39 +4,42 @@ This gem allows any class to be indexed by the chosen fulltext search engine.
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
7
|
+
Depending on the chosen engine, you need to require a dependency and then activesearch on your Gemfile:
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
And then execute:
|
9
|
+
###Mongoid
|
12
10
|
|
13
|
-
|
11
|
+
gem 'mongoid'
|
12
|
+
gem 'activesearch'
|
13
|
+
|
14
|
+
This is not a fulltext search engine, but it's a good solution for those users that don't have access to anything else.
|
15
|
+
It works by storing keywords taken from the specified fields and storing them in an Array field, which would be indexed.
|
16
|
+
|
17
|
+
###elasticsearch
|
14
18
|
|
15
|
-
|
19
|
+
gem 'tire'
|
20
|
+
gem 'activesearch'
|
16
21
|
|
17
|
-
|
22
|
+
##Configuration
|
18
23
|
|
19
|
-
|
24
|
+
Add this to your model:
|
25
|
+
|
26
|
+
search_by :title, :body, store: [:slug]
|
27
|
+
|
28
|
+
the :store option allows you to retrieve that value but it won't be used for search.
|
20
29
|
|
21
|
-
|
30
|
+
## Querying
|
31
|
+
|
32
|
+
ActiveSearch.search("some words").first.to_hash["title"]
|
33
|
+
|
34
|
+
You can access the stored fields with to_hash, so you don't need to fetch the real document.
|
22
35
|
|
23
|
-
|
24
|
-
It works by storing keywords taken from the specified fields and storing them in an Array field, which would be indexed.
|
25
|
-
search() method will return a Mongod::Criteria, so you can chain it with further scopes, like pagination.
|
26
|
-
You won't get original documents though.
|
36
|
+
## Testing
|
27
37
|
|
28
|
-
|
38
|
+
Run specs with this command:
|
29
39
|
|
30
|
-
|
31
|
-
# [...] field definitions if needed
|
32
|
-
include ActiveSearch::Engine # "Engine" being your chosen engine ie. "Mongoid"
|
33
|
-
|
34
|
-
search_on :title, :body, store: [:title]
|
35
|
-
end
|
36
|
-
|
37
|
-
# Access the stored fields so you don't need to fetch the real document
|
38
|
-
ActiveSearch.search("some words").first.stored["title"]
|
40
|
+
bundle exec parallel_rspec spec/
|
39
41
|
|
42
|
+
Since different engines define their own version of ActiveSearch, running specs on a single process will break.
|
40
43
|
|
41
44
|
## Contributing
|
42
45
|
|
data/activesearch.gemspec
CHANGED
@@ -19,5 +19,8 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.add_development_dependency "rspec"
|
21
21
|
gem.add_development_dependency "bson_ext"
|
22
|
-
gem.add_development_dependency "
|
23
|
-
|
22
|
+
gem.add_development_dependency "active_attr"
|
23
|
+
gem.add_development_dependency "mongoid", "~> 2"
|
24
|
+
gem.add_development_dependency "tire"
|
25
|
+
gem.add_development_dependency "parallel_tests"
|
26
|
+
end
|
data/elasticsearch.log
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# 2012-10-31 15:41:49:965 [HEAD] ("elastic_search_models")
|
2
|
+
#
|
3
|
+
curl -I "http://localhost:9200/elastic_search_models"
|
4
|
+
|
5
|
+
# 2012-10-31 15:41:49:988 [200]
|
6
|
+
#
|
7
|
+
# ""
|
8
|
+
|
9
|
+
# 2012-10-31 15:41:50:002 [HEAD] ("another_elastic_search_models")
|
10
|
+
#
|
11
|
+
curl -I "http://localhost:9200/another_elastic_search_models"
|
12
|
+
|
13
|
+
# 2012-10-31 15:41:50:002 [200]
|
14
|
+
#
|
15
|
+
# ""
|
16
|
+
|
17
|
+
# 2012-10-31 15:41:50:007 [_search] (["_all"])
|
18
|
+
#
|
19
|
+
curl -X GET "http://localhost:9200/_all/_search?query%5Bstring%5D=findable&pretty=true" -d '{}'
|
20
|
+
|
21
|
+
# 2012-10-31 15:41:50:008 [200] (1 msec)
|
22
|
+
#
|
23
|
+
# {"took":1,"timed_out":false,"_shards":{"total":10,"successful":10,"failed":0},"hits":{"total":0,"max_score":null,"hits":[]}}
|
24
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "activesearch/result"
|
2
|
+
|
3
|
+
module ActiveSearch
|
4
|
+
module ElasticSearch
|
5
|
+
class Proxy
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
def initialize(text)
|
9
|
+
@text = text
|
10
|
+
end
|
11
|
+
|
12
|
+
def each(&block)
|
13
|
+
search.results.each { |result| block.call(Result.new(result)) }
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def search
|
18
|
+
@search ||= Tire.search('_all') do |search|
|
19
|
+
search.query do |query|
|
20
|
+
query.text("_all", @text)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "active_support/core_ext"
|
2
|
+
require "activesearch/elastic_search/proxy"
|
3
|
+
|
4
|
+
module ActiveSearch
|
5
|
+
|
6
|
+
def self.search(text)
|
7
|
+
ElasticSearch::Proxy.new(text)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ElasticSearch
|
11
|
+
def self.included(base)
|
12
|
+
base.extend ClassMethods
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def search_by(*fields)
|
18
|
+
options = fields.pop if fields.last.is_a?(Hash)
|
19
|
+
include Tire::Model::Search
|
20
|
+
include Tire::Model::Callbacks
|
21
|
+
|
22
|
+
mapping do
|
23
|
+
indexes :type
|
24
|
+
indexes :id, as: :original_id
|
25
|
+
fields.each { |f| indexes f }
|
26
|
+
(Array(options[:store]) - fields).each { |f| indexes f, :index => :no }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -3,24 +3,28 @@ module ActiveSearch
|
|
3
3
|
class Model
|
4
4
|
include ::Mongoid::Document
|
5
5
|
|
6
|
-
field :
|
7
|
-
field :
|
8
|
-
field :
|
9
|
-
field :
|
6
|
+
field :_original_type, type: String
|
7
|
+
field :_original_id, type: BSON::ObjectId
|
8
|
+
field :_keywords
|
9
|
+
field :_stored, type: Hash, default: {}
|
10
10
|
|
11
|
-
index :
|
12
|
-
index [:
|
11
|
+
index :_keywords
|
12
|
+
index [:_original_type, :_original_id], unique: true
|
13
|
+
|
14
|
+
def to_hash
|
15
|
+
_stored
|
16
|
+
end
|
13
17
|
|
14
18
|
def store_fields(original, fields, options)
|
15
19
|
if options && options[:store]
|
16
20
|
options[:store].each do |f|
|
17
|
-
self.
|
21
|
+
self._stored[f] = original[f] if original.send("#{f}_changed?")
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
26
|
def refresh_keywords(original, fields)
|
23
|
-
self.
|
27
|
+
self._keywords = fields.select { |f| original.fields[f.to_s] }.inject([]) do |memo,f|
|
24
28
|
|
25
29
|
if original.fields[f.to_s].localized?
|
26
30
|
memo += original.send("#{f}_translations").map do |locale,translation|
|
@@ -30,11 +34,16 @@ module ActiveSearch
|
|
30
34
|
original[f] ? memo += original[f].downcase.split : memo
|
31
35
|
end
|
32
36
|
end
|
33
|
-
self.
|
37
|
+
self._keywords.uniq!
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.deindex(original)
|
41
|
+
ActiveSearch::Mongoid::Model.where(_original_type: original.class.to_s, _original_id: original.id).destroy
|
34
42
|
end
|
35
43
|
|
36
44
|
def self.reindex(original, fields, options)
|
37
|
-
|
45
|
+
return unless fields.any? { |f| original.send("#{f}_changed?") }
|
46
|
+
doc = find_or_initialize_by(_original_type: original.class.to_s, _original_id: original.id)
|
38
47
|
doc.store_fields(original, fields, options)
|
39
48
|
doc.refresh_keywords(original, fields)
|
40
49
|
doc.save
|
data/lib/activesearch/mongoid.rb
CHANGED
@@ -4,7 +4,8 @@ module ActiveSearch
|
|
4
4
|
|
5
5
|
# TODO: Wrap this so all engines behave consistently
|
6
6
|
def self.search(text)
|
7
|
-
|
7
|
+
text = text.split(/\s+/)
|
8
|
+
Mongoid::Model.where(:_keywords.in => text + text.map { |word| "#{I18n.locale}:#{word}"})
|
8
9
|
end
|
9
10
|
|
10
11
|
module Mongoid
|
@@ -12,17 +13,29 @@ module ActiveSearch
|
|
12
13
|
base.extend ClassMethods
|
13
14
|
end
|
14
15
|
|
16
|
+
protected
|
17
|
+
def reindex
|
18
|
+
ActiveSearch::Mongoid::Model.reindex(self, self.class.search_fields, self.class.search_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def deindex
|
22
|
+
ActiveSearch::Mongoid::Model.deindex(self)
|
23
|
+
end
|
24
|
+
|
15
25
|
module ClassMethods
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
def search_options
|
27
|
+
@search_options
|
28
|
+
end
|
29
|
+
|
30
|
+
def search_fields
|
31
|
+
@search_fields
|
32
|
+
end
|
33
|
+
|
34
|
+
def search_by(*fields)
|
35
|
+
@search_options = fields.pop if fields.last.is_a?(Hash)
|
36
|
+
@search_fields = fields
|
37
|
+
self.after_save :reindex
|
38
|
+
self.after_destroy :deindex
|
26
39
|
end
|
27
40
|
end
|
28
41
|
end
|
data/lib/activesearch/version.rb
CHANGED
data/lib/activesearch.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require "activesearch/version"
|
1
|
+
require "activesearch/version"
|