activesearch 0.3.1 → 0.3.2
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 +4 -4
- data/README.md +10 -8
- data/lib/activesearch/algolia.rb +20 -21
- data/lib/activesearch/algolia/client.rb +14 -2
- data/lib/activesearch/algolia/results_set.rb +30 -0
- data/lib/activesearch/algolia/worker.rb +2 -1
- data/lib/activesearch/elastic_search.rb +14 -12
- data/lib/activesearch/mongoid.rb +17 -3
- data/lib/activesearch/mongoid/full_text_search_query.rb +4 -25
- data/lib/activesearch/mongoid/index.rb +1 -1
- data/lib/activesearch/mongoid/results_set.rb +36 -0
- data/lib/activesearch/proxy.rb +10 -5
- data/lib/activesearch/results_set.rb +21 -0
- data/lib/activesearch/version.rb +1 -1
- data/spec/support/shared_examples_for_engines.rb +2 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4780fd611e6b324444174e68454b0ddcb420a98f
|
4
|
+
data.tar.gz: 6bc865f6eb2e43b5573006ca4b34ca11ffc04140
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62c93e5576610fac82d96c31b2516aa5c39697ecbe22653ce6961a51001c7d835ebbb74a6b5e735337a7b840a76c19103d0e70ebfec9f7bd422f974c318d3e29
|
7
|
+
data.tar.gz: 314d636362c96882f7cfdeb5d8fd7e5e611996e585add94e06e4047a1dd12ab255ff51064bb3414f75cb6fdb5b7cedcd32804713158f7f285b86ebbb1cd3519d
|
data/README.md
CHANGED
@@ -15,20 +15,22 @@ What lies below is for mongoid 3.x.
|
|
15
15
|
|
16
16
|
gem 'mongoid'
|
17
17
|
gem 'activesearch'
|
18
|
-
|
18
|
+
|
19
19
|
This is not a fulltext search engine, but it's a good solution for those users that don't have access to anything else.
|
20
20
|
It works by storing keywords taken from the specified fields and storing them in an Array field, which would be indexed.
|
21
|
-
|
21
|
+
|
22
22
|
###elasticsearch
|
23
23
|
|
24
24
|
gem 'tire'
|
25
25
|
gem 'activesearch'
|
26
|
-
|
26
|
+
|
27
|
+
**Important**: the elasticsearch engine has not not been updated so it does not work.
|
28
|
+
|
27
29
|
###Algolia
|
28
30
|
|
29
31
|
gem 'httparty'
|
30
32
|
gem 'activesearch'
|
31
|
-
|
33
|
+
|
32
34
|
Then you need to configure the client. In rails, put this in an algolia.rb initializer:
|
33
35
|
|
34
36
|
Algolia.configure do |c|
|
@@ -40,7 +42,7 @@ Then you need to configure the client. In rails, put this in an algolia.rb initi
|
|
40
42
|
##Configuration
|
41
43
|
|
42
44
|
call "search_by" from your model:
|
43
|
-
|
45
|
+
|
44
46
|
search_by [:title, :body, store: [:slug]], if: :its_friday
|
45
47
|
|
46
48
|
**IMPORTANT: the first parameter must be either an array, or a symbol.
|
@@ -51,7 +53,7 @@ You can also add :if or :unless conditions in the same way you would do with Act
|
|
51
53
|
If you need virtual options, pass a symbol instead:
|
52
54
|
|
53
55
|
search_by :options_for_search
|
54
|
-
|
56
|
+
|
55
57
|
And define an instance method with that name which must return an array with the options, ie:
|
56
58
|
|
57
59
|
def options_for_search
|
@@ -59,9 +61,9 @@ And define an instance method with that name which must return an array with the
|
|
59
61
|
end
|
60
62
|
|
61
63
|
## Querying
|
62
|
-
|
64
|
+
|
63
65
|
ActiveSearch.search("some words").first.to_hash["title"]
|
64
|
-
|
66
|
+
|
65
67
|
You can access the stored fields with to_hash, so you don't need to fetch the real document.
|
66
68
|
|
67
69
|
## Why?
|
data/lib/activesearch/algolia.rb
CHANGED
@@ -1,34 +1,33 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
1
|
+
require 'activesearch/base'
|
2
|
+
require 'activesearch/results_set'
|
3
|
+
require 'activesearch/proxy'
|
4
|
+
|
5
|
+
require 'activesearch/algolia/client'
|
6
|
+
require 'activesearch/algolia/results_set'
|
7
|
+
require 'activesearch/algolia/worker'
|
5
8
|
|
6
9
|
module ActiveSearch
|
7
10
|
|
8
11
|
def self.search(text, conditions = {}, options = {})
|
9
|
-
|
10
|
-
|
12
|
+
conditions.symbolize_keys!
|
13
|
+
options.symbolize_keys!
|
11
14
|
|
12
|
-
|
13
|
-
Algolia::Client.new.query(text, { tags: conditions_to_tags(conditions) }, options)["hits"].map! do |hit|
|
14
|
-
if hit["_tags"]
|
15
|
-
hit["_tags"].each do |tag|
|
16
|
-
# preserve other ":" characters
|
17
|
-
_segments = tag.split(':')
|
15
|
+
clean_locale(conditions, options)
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
hit.delete("_tags")
|
24
|
-
end
|
25
|
-
hit
|
26
|
-
end
|
27
|
-
end
|
17
|
+
results_set = Algolia::Client.new.query_text(text, { tags: conditions_to_tags(conditions) }, options)
|
18
|
+
|
19
|
+
Proxy.new(results_set, text, options)
|
28
20
|
end
|
29
21
|
|
30
22
|
protected
|
31
23
|
|
24
|
+
def self.clean_locale(conditions, options)
|
25
|
+
locale = options[:locale] || I18n.locale
|
26
|
+
conditions[:locale] ||= locale
|
27
|
+
|
28
|
+
conditions.delete(:locale) if options[:locale] == false
|
29
|
+
end
|
30
|
+
|
32
31
|
def self.conditions_to_tags(conditions)
|
33
32
|
conditions.map { |c| c.join(':') }.join(',')
|
34
33
|
end
|
@@ -28,19 +28,31 @@ module ActiveSearch
|
|
28
28
|
self.class.put("/#{id}", body: object.to_json)
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
31
|
+
def query_text(text, extras = {}, options = {})
|
32
32
|
page, per_page = options[:page] || 0, options[:per_page] || 20
|
33
33
|
|
34
|
-
self.class.get('', query: extras.merge!(
|
34
|
+
response = self.class.get('', query: extras.merge!(
|
35
35
|
query: text,
|
36
36
|
page: page,
|
37
37
|
hitsPerPage: per_page
|
38
38
|
))
|
39
|
+
|
40
|
+
ResultsSet.new(response, page, per_page)
|
39
41
|
end
|
40
42
|
|
41
43
|
def get(id)
|
42
44
|
self.class.get("/#{id}")
|
43
45
|
end
|
46
|
+
|
47
|
+
def find_from_resource(type, id, &block)
|
48
|
+
query = {
|
49
|
+
tags: "original_type:#{type},original_id:#{id}",
|
50
|
+
query: ''
|
51
|
+
}
|
52
|
+
|
53
|
+
self.class.get('', query: query)['hits'].each(&block)
|
54
|
+
end
|
55
|
+
|
44
56
|
end
|
45
57
|
end
|
46
58
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActiveSearch
|
2
|
+
module Algolia
|
3
|
+
class ResultsSet < ActiveSearch::ResultsSet
|
4
|
+
|
5
|
+
def initialize(results, page = nil, per_page = nil)
|
6
|
+
super
|
7
|
+
|
8
|
+
@results = results['hits']
|
9
|
+
@total_entries = results['nbHits']
|
10
|
+
@total_pages = results['hitsPerPage']
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(result)
|
14
|
+
if result['_tags']
|
15
|
+
result['_tags'].each do |tag|
|
16
|
+
# preserve other ":" characters
|
17
|
+
_segments = tag.split(':')
|
18
|
+
|
19
|
+
unless _segments.empty? || _segments[1..-1].empty?
|
20
|
+
result[_segments.first] = _segments[1..-1].join(':')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
result.delete("_tags")
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -10,7 +10,8 @@ class ActiveSearch::Algolia::Worker
|
|
10
10
|
::ActiveSearch::Algolia::Client.new.save(msg[:id], msg[:doc])
|
11
11
|
when :deindex
|
12
12
|
client = ::ActiveSearch::Algolia::Client.new
|
13
|
-
|
13
|
+
|
14
|
+
client.find_from_resource(msg[:type], msg[:id]).each do |hit|
|
14
15
|
client.delete(hit["objectID"])
|
15
16
|
end
|
16
17
|
end
|
@@ -4,8 +4,10 @@ require "activesearch/base"
|
|
4
4
|
require "activesearch/proxy"
|
5
5
|
|
6
6
|
module ActiveSearch
|
7
|
-
|
7
|
+
|
8
8
|
def self.search(text)
|
9
|
+
raise 'sorry but it is not implemented'
|
10
|
+
|
9
11
|
Proxy.new(text) do |text|
|
10
12
|
Tire.search('_all') do |search|
|
11
13
|
search.query do |query|
|
@@ -14,33 +16,33 @@ module ActiveSearch
|
|
14
16
|
end.results
|
15
17
|
end
|
16
18
|
end
|
17
|
-
|
19
|
+
|
18
20
|
module ElasticSearch
|
19
21
|
def self.included(base)
|
20
22
|
base.class_eval do
|
21
23
|
include ActiveSearch::Base
|
22
24
|
end
|
23
25
|
end
|
24
|
-
|
26
|
+
|
25
27
|
def to_indexable
|
26
28
|
elastic_properties.keys.inject({_type: self.elastic_type}) do |memo,field|
|
27
29
|
memo.merge!(field => self.send(field))
|
28
30
|
end
|
29
31
|
end
|
30
|
-
|
32
|
+
|
31
33
|
protected
|
32
34
|
def elastic_type
|
33
35
|
@elastic_type ||= self.type.gsub!(/(.)([A-Z])/,'\1_\2').downcase
|
34
36
|
end
|
35
|
-
|
37
|
+
|
36
38
|
def elastic_index(&block)
|
37
39
|
Tire.index(elastic_type, &block)
|
38
40
|
end
|
39
|
-
|
41
|
+
|
40
42
|
def reindex
|
41
43
|
doc = self.to_indexable
|
42
44
|
properties = self.elastic_properties
|
43
|
-
|
45
|
+
|
44
46
|
elastic_index do
|
45
47
|
unless exists?
|
46
48
|
create({ mappings: { doc[:_type] => {properties: properties}}})
|
@@ -48,25 +50,25 @@ module ActiveSearch
|
|
48
50
|
store doc
|
49
51
|
end
|
50
52
|
end
|
51
|
-
|
53
|
+
|
52
54
|
def deindex
|
53
55
|
doc = self.to_indexable
|
54
56
|
elastic_index do
|
55
57
|
remove doc
|
56
58
|
end
|
57
59
|
end
|
58
|
-
|
60
|
+
|
59
61
|
def elastic_properties
|
60
62
|
props = {id: {type: 'string'}}
|
61
|
-
|
63
|
+
|
62
64
|
search_fields.each_with_object(props) do |field,hash|
|
63
65
|
hash[field] = {type: 'string'}
|
64
66
|
end
|
65
|
-
|
67
|
+
|
66
68
|
(Array(search_options[:store]) - search_fields).each_with_object(props) do |field,hash|
|
67
69
|
hash[field] = {type: 'string', :index => :no}
|
68
70
|
end
|
69
|
-
|
71
|
+
|
70
72
|
props
|
71
73
|
end
|
72
74
|
end
|
data/lib/activesearch/mongoid.rb
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
require 'activesearch/base'
|
2
|
+
require 'activesearch/results_set'
|
2
3
|
require 'activesearch/proxy'
|
4
|
+
|
5
|
+
require 'activesearch/mongoid/results_set'
|
3
6
|
require 'activesearch/mongoid/full_text_search_query'
|
4
7
|
require 'activesearch/mongoid/index'
|
5
8
|
|
6
9
|
module ActiveSearch
|
7
10
|
|
8
11
|
def self.search(text, conditions = {}, options = {})
|
12
|
+
conditions.symbolize_keys!
|
13
|
+
options.symbolize_keys!
|
14
|
+
|
15
|
+
clean_locale(conditions, options)
|
16
|
+
|
17
|
+
results_set = ActiveSearch::Mongoid::Index.search(text, conditions, options)
|
18
|
+
|
19
|
+
Proxy.new(results_set, text, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def self.clean_locale(conditions, options)
|
9
25
|
locale = options[:locale] || I18n.locale
|
10
26
|
conditions[:locale] ||= locale
|
11
27
|
|
12
|
-
|
13
|
-
ActiveSearch::Mongoid::Index.search(text, conditions, options)
|
14
|
-
end
|
28
|
+
conditions.delete(:locale) if options[:locale] == false
|
15
29
|
end
|
16
30
|
|
17
31
|
module Mongoid
|
@@ -2,8 +2,6 @@ module ActiveSearch
|
|
2
2
|
module Mongoid
|
3
3
|
class FullTextSearchQuery
|
4
4
|
|
5
|
-
attr_reader :results
|
6
|
-
|
7
5
|
def initialize(name, query, conditions, options)
|
8
6
|
@name = name
|
9
7
|
@query = query
|
@@ -13,18 +11,14 @@ module ActiveSearch
|
|
13
11
|
end
|
14
12
|
|
15
13
|
def run
|
16
|
-
|
14
|
+
results = session.command({
|
17
15
|
'text' => @name,
|
18
16
|
'search' => @query,
|
19
17
|
'language' => @language,
|
20
18
|
'filter' => @filter
|
21
19
|
})
|
22
20
|
|
23
|
-
|
24
|
-
sanitize_results
|
25
|
-
else
|
26
|
-
[]
|
27
|
-
end
|
21
|
+
ResultsSet.new(results, @options[:page], @options[:per_page])
|
28
22
|
end
|
29
23
|
|
30
24
|
def session
|
@@ -57,8 +51,8 @@ module ActiveSearch
|
|
57
51
|
def prepare_filter(conditions)
|
58
52
|
{}.tap do |filter|
|
59
53
|
conditions.each do |key, value|
|
60
|
-
if key == :locale
|
61
|
-
filter['locale'] = value.to_s
|
54
|
+
if key.to_sym == :locale
|
55
|
+
filter['locale'] = value.to_s unless value == false
|
62
56
|
else
|
63
57
|
filter["stored.#{key}"] = value
|
64
58
|
end
|
@@ -66,21 +60,6 @@ module ActiveSearch
|
|
66
60
|
end
|
67
61
|
end
|
68
62
|
|
69
|
-
def sanitize_results
|
70
|
-
page, per_page = @options[:page] || 0, @options[:per_page] || 10
|
71
|
-
included = ((page * per_page)..((page + 1) * per_page - 1))
|
72
|
-
_results = []
|
73
|
-
|
74
|
-
# manual pagination since it is not natively supported by MongoDB
|
75
|
-
@results['results'].each_with_index do |result, index|
|
76
|
-
if included === index
|
77
|
-
_results << result['obj']['stored'].merge(result['obj'].slice('locale', 'original_type', 'original_id'))
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
@results = _results
|
82
|
-
end
|
83
|
-
|
84
63
|
end
|
85
64
|
end
|
86
65
|
end
|
@@ -63,7 +63,7 @@ module ActiveSearch
|
|
63
63
|
doc = find_or_initialize_by(original_type: original.class.to_s, original_id: original.id, locale: locale)
|
64
64
|
|
65
65
|
doc.store_language(original)
|
66
|
-
doc.store_fields(original)
|
66
|
+
doc.store_fields(original)
|
67
67
|
doc.refresh_content(original)
|
68
68
|
|
69
69
|
# save it (create or update it)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveSearch
|
2
|
+
module Mongoid
|
3
|
+
class ResultsSet < ActiveSearch::ResultsSet
|
4
|
+
|
5
|
+
def initialize(results, page = nil, per_page = nil)
|
6
|
+
super
|
7
|
+
|
8
|
+
@results = results.has_key?('results') ? results['results'] : []
|
9
|
+
@total_entries = @results.size
|
10
|
+
@total_pages = @total_entries / @per_page
|
11
|
+
|
12
|
+
self.paginate if @total_entries > 0
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def index_range
|
18
|
+
((@page * @per_page)..((@page + 1) * @per_page - 1))
|
19
|
+
end
|
20
|
+
|
21
|
+
def paginate
|
22
|
+
_results = []
|
23
|
+
|
24
|
+
# manual pagination since it is not natively supported by MongoDB
|
25
|
+
@results.each_with_index do |result, index|
|
26
|
+
if index_range === index
|
27
|
+
_results << result['obj']['stored'].merge(result['obj'].slice('locale', 'original_type', 'original_id'))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@results = _results
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/activesearch/proxy.rb
CHANGED
@@ -4,17 +4,22 @@ module ActiveSearch
|
|
4
4
|
class Proxy
|
5
5
|
include Enumerable
|
6
6
|
|
7
|
-
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@results_set, :total_pages, :total_entries, :per_page, :page
|
10
|
+
|
11
|
+
def initialize(results_set, text, options)
|
12
|
+
@results_set = results_set
|
8
13
|
@text = text
|
9
|
-
@conditions = conditions
|
10
14
|
@options = options
|
11
|
-
@implementation = implementation
|
12
15
|
end
|
13
16
|
|
14
17
|
def each(&block)
|
15
|
-
@
|
16
|
-
|
18
|
+
@results_set.results.map do |result|
|
19
|
+
_result = @results_set.parse(result)
|
20
|
+
block.call(Result.new(_result, @text, @options))
|
17
21
|
end
|
18
22
|
end
|
23
|
+
|
19
24
|
end
|
20
25
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveSearch
|
2
|
+
class ResultsSet
|
3
|
+
|
4
|
+
attr_reader :results, :total_entries, :total_pages, :page, :per_page
|
5
|
+
|
6
|
+
def initialize(results, page = nil, per_page = nil)
|
7
|
+
@results = results
|
8
|
+
@page = page || 0
|
9
|
+
@per_page = per_page || 10
|
10
|
+
end
|
11
|
+
|
12
|
+
def define_parser(&block)
|
13
|
+
@parser = block
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse(result)
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/activesearch/version.rb
CHANGED
@@ -64,6 +64,8 @@ shared_examples 'an engine' do
|
|
64
64
|
it "should paginate docs" do
|
65
65
|
page = ActiveSearch.search("findable", {}, { page: 0, per_page: 2 })
|
66
66
|
first_page_titles = page.map { |e| e['title'] }
|
67
|
+
page.total_entries.should == 5
|
68
|
+
page.total_pages.should == 2
|
67
69
|
page.count.should == 2
|
68
70
|
|
69
71
|
page = ActiveSearch.search("findable", {}, { page: 1, per_page: 2 })
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activesearch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Alvarez
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-04-
|
12
|
+
date: 2014-04-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -199,14 +199,17 @@ files:
|
|
199
199
|
- lib/activesearch.rb
|
200
200
|
- lib/activesearch/algolia.rb
|
201
201
|
- lib/activesearch/algolia/client.rb
|
202
|
+
- lib/activesearch/algolia/results_set.rb
|
202
203
|
- lib/activesearch/algolia/worker.rb
|
203
204
|
- lib/activesearch/base.rb
|
204
205
|
- lib/activesearch/elastic_search.rb
|
205
206
|
- lib/activesearch/mongoid.rb
|
206
207
|
- lib/activesearch/mongoid/full_text_search_query.rb
|
207
208
|
- lib/activesearch/mongoid/index.rb
|
209
|
+
- lib/activesearch/mongoid/results_set.rb
|
208
210
|
- lib/activesearch/proxy.rb
|
209
211
|
- lib/activesearch/result.rb
|
212
|
+
- lib/activesearch/results_set.rb
|
210
213
|
- lib/activesearch/version.rb
|
211
214
|
- spec/config/mongoid.yml
|
212
215
|
- spec/engines/algolia_spec.rb
|