activesearch 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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
- Add this line to your application's Gemfile:
7
+ Depending on the chosen engine, you need to require a dependency and then activesearch on your Gemfile:
8
8
 
9
- gem 'activesearch'
10
-
11
- And then execute:
9
+ ###Mongoid
12
10
 
13
- $ bundle
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
- Or install it yourself as:
19
+ gem 'tire'
20
+ gem 'activesearch'
16
21
 
17
- $ gem install activesearch
22
+ ##Configuration
18
23
 
19
- ## Supported engines
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
- ###Mongoid
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
- This is not a fulltext search engine, but it's a good solution for those users that don't have access to anything else.
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
- ## Usage
38
+ Run specs with this command:
29
39
 
30
- class SomeModel
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 "mongoid", "~> 2.4"
23
- end
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 :type, type: String
7
- field :original_id, type: BSON::ObjectId
8
- field :keywords
9
- field :stored, type: Hash, default: {}
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 :keywords
12
- index [:type, :original_id], unique: true
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.stored[f] = original[f] if original.send("#{f}_changed?")
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.keywords = fields.select { |f| original.fields[f.to_s] }.inject([]) do |memo,f|
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.keywords.uniq!
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
- doc = self.find_or_initialize_by(type: original.class.to_s, original_id: original.id)
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
@@ -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
- Mongoid::Model.where(:keywords.in => text.split + text.split.map { |word| "#{I18n.locale}:#{word}"})
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 search_on(*fields)
17
- # TODO: Use inheritable class variables, so ActiveSearch::Mongoid::Model can get fields and options from there
18
- self.class_eval <<-EOV
19
- after_save do
20
- fields = #{fields}
21
- options = fields.pop if fields.last.is_a?(Hash)
22
- return unless fields.any? { |f| self.send("\#{f}_changed?") }
23
- ActiveSearch::Mongoid::Model.reindex(self, fields, options)
24
- end
25
- EOV
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
@@ -0,0 +1,13 @@
1
+ module ActiveSearch
2
+ class Result < Hash
3
+ def initialize(result)
4
+ result.to_hash.each do |k,v|
5
+ self[k.to_s] = v unless v.nil?
6
+ end
7
+ end
8
+
9
+ def attributes
10
+ self
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveSearch
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/activesearch.rb CHANGED
@@ -1 +1 @@
1
- require "activesearch/version"
1
+ require "activesearch/version"