outoftime-sunspot 0.0.1
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/History.txt +7 -0
- data/Manifest.txt +104 -0
- data/PostInstall.txt +7 -0
- data/README.rdoc +115 -0
- data/Rakefile +27 -0
- data/config/hoe.rb +74 -0
- data/config/requirements.rb +15 -0
- data/lib/light_config.rb +40 -0
- data/lib/sunspot/adapters.rb +54 -0
- data/lib/sunspot/conditions.rb +50 -0
- data/lib/sunspot/conditions_builder.rb +37 -0
- data/lib/sunspot/configuration.rb +17 -0
- data/lib/sunspot/field.rb +108 -0
- data/lib/sunspot/field_builder.rb +37 -0
- data/lib/sunspot/indexer.rb +65 -0
- data/lib/sunspot/query.rb +115 -0
- data/lib/sunspot/query_builder.rb +30 -0
- data/lib/sunspot/restriction.rb +72 -0
- data/lib/sunspot/scope_builder.rb +33 -0
- data/lib/sunspot/search.rb +83 -0
- data/lib/sunspot/session.rb +43 -0
- data/lib/sunspot/type.rb +62 -0
- data/lib/sunspot/util.rb +13 -0
- data/lib/sunspot/version.rb +10 -0
- data/lib/sunspot.rb +50 -0
- data/setup.rb +1585 -0
- data/solr/README.txt +36 -0
- data/solr/etc/jetty.xml +206 -0
- data/solr/etc/webdefault.xml +379 -0
- data/solr/exampledocs/books.csv +11 -0
- data/solr/exampledocs/hd.xml +46 -0
- data/solr/exampledocs/ipod_other.xml +50 -0
- data/solr/exampledocs/ipod_video.xml +35 -0
- data/solr/exampledocs/mem.xml +58 -0
- data/solr/exampledocs/monitor.xml +31 -0
- data/solr/exampledocs/monitor2.xml +30 -0
- data/solr/exampledocs/mp500.xml +39 -0
- data/solr/exampledocs/post.jar +0 -0
- data/solr/exampledocs/post.sh +28 -0
- data/solr/exampledocs/sd500.xml +33 -0
- data/solr/exampledocs/solr.xml +38 -0
- data/solr/exampledocs/spellchecker.xml +58 -0
- data/solr/exampledocs/utf8-example.xml +42 -0
- data/solr/exampledocs/vidcard.xml +52 -0
- data/solr/lib/jetty-6.1.3.jar +0 -0
- data/solr/lib/jetty-util-6.1.3.jar +0 -0
- data/solr/lib/jsp-2.1/ant-1.6.5.jar +0 -0
- data/solr/lib/jsp-2.1/core-3.1.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-2.1.jar +0 -0
- data/solr/lib/jsp-2.1/jsp-api-2.1.jar +0 -0
- data/solr/lib/servlet-api-2.5-6.1.3.jar +0 -0
- data/solr/solr/README.txt +52 -0
- data/solr/solr/bin/abc +176 -0
- data/solr/solr/bin/abo +176 -0
- data/solr/solr/bin/backup +108 -0
- data/solr/solr/bin/backupcleaner +142 -0
- data/solr/solr/bin/commit +128 -0
- data/solr/solr/bin/optimize +129 -0
- data/solr/solr/bin/readercycle +129 -0
- data/solr/solr/bin/rsyncd-disable +77 -0
- data/solr/solr/bin/rsyncd-enable +76 -0
- data/solr/solr/bin/rsyncd-start +145 -0
- data/solr/solr/bin/rsyncd-stop +105 -0
- data/solr/solr/bin/scripts-util +83 -0
- data/solr/solr/bin/snapcleaner +148 -0
- data/solr/solr/bin/snapinstaller +168 -0
- data/solr/solr/bin/snappuller +248 -0
- data/solr/solr/bin/snappuller-disable +77 -0
- data/solr/solr/bin/snappuller-enable +77 -0
- data/solr/solr/bin/snapshooter +109 -0
- data/solr/solr/conf/admin-extra.html +31 -0
- data/solr/solr/conf/protwords.txt +21 -0
- data/solr/solr/conf/schema.xml +231 -0
- data/solr/solr/conf/scripts.conf +24 -0
- data/solr/solr/conf/solrconfig.xml +394 -0
- data/solr/solr/conf/stopwords.txt +57 -0
- data/solr/solr/conf/synonyms.txt +31 -0
- data/solr/start.jar +0 -0
- data/solr/webapps/solr.war +0 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rcov.rake +6 -0
- data/tasks/solr.rake +12 -0
- data/tasks/website.rake +17 -0
- data/test/api/test_build_search.rb +216 -0
- data/test/api/test_helper.rb +4 -0
- data/test/api/test_indexer.rb +110 -0
- data/test/api/test_retrieve_search.rb +114 -0
- data/test/api/test_session.rb +46 -0
- data/test/custom_expectation.rb +53 -0
- data/test/integration/test_field_types.rb +62 -0
- data/test/integration/test_helper.rb +1 -0
- data/test/integration/test_keyword_search.rb +32 -0
- data/test/integration/test_pagination.rb +32 -0
- data/test/mocks/base_class.rb +2 -0
- data/test/mocks/comment.rb +28 -0
- data/test/mocks/mock_adapter.rb +25 -0
- data/test/mocks/post.rb +41 -0
- data/test/test_helper.rb +31 -0
- metadata +191 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class FieldBuilder
|
|
3
|
+
def initialize(clazz)
|
|
4
|
+
@clazz = clazz
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def text(*names, &block)
|
|
8
|
+
for name in names
|
|
9
|
+
::Sunspot::Field.register_text clazz, build_field(name, ::Sunspot::Type::TextType, &block)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def method_missing(method, *args, &block)
|
|
14
|
+
begin
|
|
15
|
+
type = ::Sunspot::Type.const_get "#{method.to_s.camel_case}Type"
|
|
16
|
+
rescue(NameError)
|
|
17
|
+
super(method.to_sym, *args, &block) and return
|
|
18
|
+
end
|
|
19
|
+
name = args.shift
|
|
20
|
+
::Sunspot::Field.register clazz, build_field(name, type, *args, &block)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
protected
|
|
24
|
+
attr_reader :clazz
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def build_field(name, type, *args, &block)
|
|
29
|
+
options = args.shift if args.first.is_a?(Hash)
|
|
30
|
+
unless block
|
|
31
|
+
::Sunspot::Field::AttributeField.new(name, type, options || {})
|
|
32
|
+
else
|
|
33
|
+
::Sunspot::Field::VirtualField.new(name, type, options || {}, &block)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class Indexer
|
|
3
|
+
def initialize(connection)
|
|
4
|
+
@connection = connection
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def add(model)
|
|
8
|
+
hash = static_hash_for model
|
|
9
|
+
for field in fields
|
|
10
|
+
hash.merge! field.pair_for(model)
|
|
11
|
+
end
|
|
12
|
+
connection.add hash
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def fields
|
|
16
|
+
@fields ||= []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def add_fields(fields)
|
|
20
|
+
self.fields.concat fields
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def remove(model)
|
|
24
|
+
connection.delete(::Sunspot::Adapters.adapt_instance(model).index_id)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
attr_reader :connection
|
|
29
|
+
|
|
30
|
+
def static_hash_for(model)
|
|
31
|
+
{ :id => ::Sunspot::Adapters.adapt_instance(model).index_id,
|
|
32
|
+
:type => Indexer.superclasses_for(model.class).map { |clazz| clazz.name }}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class <<Indexer
|
|
37
|
+
def add(connection, model)
|
|
38
|
+
self.for(model.class, connection).add(model)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def remove(connection, model)
|
|
42
|
+
self.for(model.class, connection).remove(model)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def remove_all(connection, clazz = nil)
|
|
46
|
+
connection.delete_by_query("type:#{clazz ? clazz.name : '[* TO *]'}")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def for(clazz, connection)
|
|
50
|
+
indexer = self.new(connection)
|
|
51
|
+
for superclass in superclasses_for(clazz)
|
|
52
|
+
indexer.add_fields ::Sunspot::Field.for(superclass)
|
|
53
|
+
indexer.add_fields ::Sunspot::Field.text_for(superclass)
|
|
54
|
+
end
|
|
55
|
+
raise ArgumentError, "Class #{clazz.name} has not been configured for indexing" if indexer.fields.empty?
|
|
56
|
+
indexer
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def superclasses_for(clazz)
|
|
60
|
+
superclasses_for = [clazz]
|
|
61
|
+
superclasses_for << (clazz = clazz.superclass) while clazz.superclass != Object
|
|
62
|
+
superclasses_for
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class Query
|
|
3
|
+
attr_accessor :keywords, :conditions, :rows, :start, :sort
|
|
4
|
+
|
|
5
|
+
def initialize(types, params, configuration)
|
|
6
|
+
@keywords, @types, @configuration = params[:keywords], types, configuration
|
|
7
|
+
@conditions = Sunspot::Conditions.new(self, params[:conditions] || {})
|
|
8
|
+
paginate(params[:page], params[:per_page])
|
|
9
|
+
self.order = params[:order] if params[:order]
|
|
10
|
+
attributes[:keywords] = @keywords
|
|
11
|
+
params[:conditions].each_pair do |field_name, value|
|
|
12
|
+
attributes[:conditions][field_name.to_sym] = value
|
|
13
|
+
end if params[:conditions]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_solr
|
|
17
|
+
query_components = []
|
|
18
|
+
query_components << keywords if keywords
|
|
19
|
+
query_components << types_query if types_query
|
|
20
|
+
query_components.map { |component| "(#{component})"} * ' AND '
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def filter_queries
|
|
24
|
+
scope_queries + condition_queries
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def add_scope(condition)
|
|
28
|
+
scope << condition
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_condition(field_name, condition_clazz, value)
|
|
32
|
+
condition_clazz.new(field(field_name), value)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def paginate(page = nil, per_page = nil)
|
|
36
|
+
page ||= 1
|
|
37
|
+
per_page ||= configuration.pagination.default_per_page
|
|
38
|
+
@start = (page - 1) * per_page
|
|
39
|
+
@rows = per_page
|
|
40
|
+
attributes[:page], attributes[:per_page] = page, per_page
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def order=(order)
|
|
44
|
+
order_by(*order.split(' '))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def order_by(field_name, direction = nil)
|
|
48
|
+
direction ||= :asc
|
|
49
|
+
@sort = [{ field(field_name).indexed_name.to_sym => (direction.to_s == 'asc' ? :ascending : :descending) }] #TODO should support multiple order columns
|
|
50
|
+
attributes[:order] = "#{field_name} #{direction}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def page
|
|
54
|
+
return nil unless start && rows
|
|
55
|
+
start / rows + 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def attributes
|
|
59
|
+
@attributes ||= {
|
|
60
|
+
:order => nil,
|
|
61
|
+
:conditions => fields_hash.keys.inject({}) { |conditions, key| conditions[key.to_sym] = nil; conditions }
|
|
62
|
+
}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
alias_method :per_page, :rows
|
|
66
|
+
|
|
67
|
+
protected
|
|
68
|
+
attr_accessor :types, :configuration
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def scope
|
|
73
|
+
@scope ||= []
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def scope_queries
|
|
77
|
+
scope.map { |condition| condition.to_solr_query }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def condition_queries
|
|
81
|
+
conditions.restrictions.map { |condition| condition.to_solr_query }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def types_query
|
|
85
|
+
if types.nil? || types.empty? then "type:[* TO *]"
|
|
86
|
+
elsif types.length == 1 then "type:#{types.first}"
|
|
87
|
+
else "type:(#{types * ' OR '})"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def field(field_name)
|
|
92
|
+
fields_hash[field_name.to_s] || raise(ArgumentError, "No field configured for #{types * ', '} with name '#{field_name}'")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def fields_hash
|
|
96
|
+
@fields_hash ||= begin
|
|
97
|
+
fields_hash = types.inject({}) do |hash, type|
|
|
98
|
+
::Sunspot::Field.for(type).each do |field|
|
|
99
|
+
(hash[field.name.to_s] ||= {})[type.name] = field
|
|
100
|
+
end
|
|
101
|
+
hash
|
|
102
|
+
end
|
|
103
|
+
fields_hash.each_pair do |field_name, field_configurations_hash|
|
|
104
|
+
if types.any? { |type| field_configurations_hash[type.name].nil? } # at least one type doesn't have this field configured
|
|
105
|
+
fields_hash.delete(field_name)
|
|
106
|
+
elsif field_configurations_hash.values.map { |configuration| configuration.indexed_name }.uniq.length != 1 # fields with this name have different configs
|
|
107
|
+
fields_hash.delete(field_name)
|
|
108
|
+
else
|
|
109
|
+
fields_hash[field_name] = field_configurations_hash.values.first
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class QueryBuilder
|
|
3
|
+
def initialize(query)
|
|
4
|
+
@query = query
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def keywords(keywords)
|
|
8
|
+
@query.keywords = keywords
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def with
|
|
12
|
+
@conditions_builder ||= ::Sunspot::ScopeBuilder.new(@query)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def conditions
|
|
16
|
+
@query.conditions
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def paginate(options = {})
|
|
20
|
+
page = options.delete(:page) || raise(ArgumentError, "paginate requires a :page argument")
|
|
21
|
+
per_page = options.delete(:per_page)
|
|
22
|
+
raise ArgumentError, "unknown argument #{options.keys.first.inspect} passed to paginate" unless options.empty?
|
|
23
|
+
@query.paginate(page, per_page)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def order_by(field_name, direction = nil)
|
|
27
|
+
@query.order_by(field_name, direction)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module Restriction
|
|
3
|
+
class Base
|
|
4
|
+
def initialize(field, value)
|
|
5
|
+
@field, @value = field, value
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def to_solr_query
|
|
9
|
+
"#{field.indexed_name}:#{to_solr_conditional}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
attr_accessor :field, :value
|
|
14
|
+
|
|
15
|
+
def solr_value(value = self.value)
|
|
16
|
+
escape field.to_indexed(value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def escape(value)
|
|
20
|
+
Solr::Util.query_parser_escape value
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class EqualTo < Base
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def to_solr_conditional
|
|
28
|
+
"#{solr_value}"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class LessThan < Base
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def to_solr_conditional
|
|
36
|
+
"[* TO #{solr_value}]"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class GreaterThan < Base
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def to_solr_conditional
|
|
44
|
+
"[#{solr_value} TO *]"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class Between < Base
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def to_solr_conditional
|
|
52
|
+
"[#{solr_value value.first} TO #{solr_value value.last}]"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class AnyOf < Base
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def to_solr_conditional
|
|
60
|
+
"(#{value.map { |v| solr_value v } * ' OR '})"
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class AllOf < Base
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def to_solr_conditional
|
|
68
|
+
"(#{value.map { |v| solr_value v } * ' AND '})"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class ScopeBuilder
|
|
3
|
+
def initialize(query)
|
|
4
|
+
@query = query
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def method_missing(field_name, *args)
|
|
8
|
+
if args.length == 0 then RestrictionBuilder.new(field_name, @query)
|
|
9
|
+
elsif args.length == 1 then @query.add_scope @query.build_condition(field_name, ::Sunspot::Restriction::EqualTo, args.first)
|
|
10
|
+
else super(field_name.to_sym, *args)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class RestrictionBuilder
|
|
15
|
+
def initialize(field_name, query)
|
|
16
|
+
@field_name, @query = field_name, query
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def method_missing(condition_name, *args)
|
|
20
|
+
clazz = begin
|
|
21
|
+
::Sunspot::Restriction.const_get(condition_name.to_s.camel_case)
|
|
22
|
+
rescue(NameError)
|
|
23
|
+
super(condition_name.to_sym, *args)
|
|
24
|
+
end
|
|
25
|
+
if value = args.first
|
|
26
|
+
@query.add_scope @query.build_condition(@field_name, clazz, args.first)
|
|
27
|
+
else
|
|
28
|
+
@query.interpret_condition @field_name, clazz
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class Search
|
|
3
|
+
def initialize(connection, configuration, *types, &block)
|
|
4
|
+
@connection = connection
|
|
5
|
+
params = types.last.is_a?(Hash) ? types.pop : {}
|
|
6
|
+
@query = Sunspot::Query.new(types, params, configuration)
|
|
7
|
+
QueryBuilder.new(@query).instance_eval(&block) if block
|
|
8
|
+
@types = types
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def execute!
|
|
12
|
+
query_options = {}
|
|
13
|
+
query_options[:filter_queries] = query.filter_queries
|
|
14
|
+
query_options[:rows] = query.rows
|
|
15
|
+
query_options[:start] = query.start if query.start
|
|
16
|
+
query_options[:sort] = query.sort if query.sort
|
|
17
|
+
@solr_result = connection.query(query.to_solr, query_options)
|
|
18
|
+
self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def results
|
|
22
|
+
@results ||= if query.page && defined?(WillPaginate::Collection)
|
|
23
|
+
WillPaginate::Collection.create(query.page, query.per_page, @solr_result.total_hits) do |pager|
|
|
24
|
+
pager.replace(result_objects)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
result_objects
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def total
|
|
32
|
+
@total ||= @solr_result.total_hits
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def attributes
|
|
36
|
+
@query.attributes
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def order
|
|
40
|
+
@query.attributes[:order]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def page
|
|
44
|
+
@query.attributes[:page]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def per_page
|
|
48
|
+
@query.attributes[:per_page]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def keywords
|
|
52
|
+
@query.attributes[:keywords]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def conditions
|
|
56
|
+
::Sunspot::Util::ClosedStruct.new(@query.attributes[:conditions])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
protected
|
|
60
|
+
attr_reader :query, :types, :connection
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def result_objects
|
|
65
|
+
hit_ids = @solr_result.hits.map { |hit| hit['id'] }
|
|
66
|
+
hit_ids.inject({}) do |type_id_hash, hit_id|
|
|
67
|
+
match = /([^ ]+) (.+)/.match hit_id
|
|
68
|
+
(type_id_hash[match[1]] ||= []) << match[2]
|
|
69
|
+
type_id_hash
|
|
70
|
+
end.inject([]) do |results, pair|
|
|
71
|
+
type_name, ids = pair
|
|
72
|
+
results.concat ::Sunspot::Adapters.adapt_class(type_with_name(type_name)).load_all(ids)
|
|
73
|
+
end.sort_by do |result|
|
|
74
|
+
hit_ids.index(::Sunspot::Adapters.adapt_instance(result).index_id)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def type_with_name(type_name)
|
|
79
|
+
@types_cache ||= {}
|
|
80
|
+
@types_cache[type_name] ||= type_name.split('::').inject(Module) { |namespace, name| namespace.const_get(name) }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
class Session
|
|
3
|
+
attr_reader :config
|
|
4
|
+
|
|
5
|
+
def initialize(config = Sunspot::Configuration.build, connection = nil)
|
|
6
|
+
@config = config
|
|
7
|
+
yield(@config) if block_given?
|
|
8
|
+
@connection = connection
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def search(*types, &block)
|
|
12
|
+
::Sunspot::Search.new(connection, @config, *types, &block).execute!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def index(*objects)
|
|
16
|
+
for object in objects
|
|
17
|
+
::Sunspot::Indexer.add(connection, object)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def remove(*objects)
|
|
22
|
+
for object in objects
|
|
23
|
+
::Sunspot::Indexer.remove(connection, object)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def remove_all(*classes)
|
|
28
|
+
if classes.empty?
|
|
29
|
+
::Sunspot::Indexer.remove_all(connection)
|
|
30
|
+
else
|
|
31
|
+
classes.each do |clazz|
|
|
32
|
+
::Sunspot::Indexer.remove_all(connection, clazz)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def connection
|
|
40
|
+
@connection ||= Solr::Connection.new(config.solr.url, :autocommit => :on)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/sunspot/type.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module Type
|
|
3
|
+
TextType = Module.new
|
|
4
|
+
StringType = Module.new
|
|
5
|
+
IntegerType = Module.new
|
|
6
|
+
FloatType = Module.new
|
|
7
|
+
TimeType = Module.new
|
|
8
|
+
|
|
9
|
+
class <<TextType
|
|
10
|
+
def indexed_name(name)
|
|
11
|
+
"#{name}_text"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_indexed(value)
|
|
15
|
+
value.to_s if value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class <<StringType
|
|
20
|
+
def indexed_name(name)
|
|
21
|
+
"#{name}_s"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_indexed(value)
|
|
25
|
+
value.to_s if value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class <<IntegerType
|
|
30
|
+
def indexed_name(name)
|
|
31
|
+
"#{name}_i"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_indexed(value)
|
|
35
|
+
value.to_i.to_s if value
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class <<FloatType
|
|
40
|
+
def indexed_name(name)
|
|
41
|
+
"#{name}_f"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_indexed(value)
|
|
45
|
+
value.to_f.to_s if value
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class <<TimeType
|
|
50
|
+
def indexed_name(name)
|
|
51
|
+
"#{name}_d"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_indexed(value)
|
|
55
|
+
if value
|
|
56
|
+
time = value.respond_to?(:to_time) ? value.to_time : Time.parse(value.to_s)
|
|
57
|
+
time.utc.strftime('%FT%TZ')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/sunspot/util.rb
ADDED
data/lib/sunspot.rb
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
gem 'solr-ruby'
|
|
3
|
+
gem 'extlib'
|
|
4
|
+
require 'solr'
|
|
5
|
+
require 'extlib'
|
|
6
|
+
require File.join(File.dirname(__FILE__), 'light_config')
|
|
7
|
+
|
|
8
|
+
%w(adapters restriction conditions configuration field field_builder indexer query query_builder scope_builder search session type util).each do |filename|
|
|
9
|
+
require File.join(File.dirname(__FILE__), 'sunspot', filename)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module Sunspot
|
|
13
|
+
VERSION='0.0.1'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class <<Sunspot
|
|
17
|
+
def setup(clazz, &block)
|
|
18
|
+
::Sunspot::FieldBuilder.new(clazz).instance_eval(&block) if block
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def index(*objects)
|
|
22
|
+
session.index(*objects)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def search(*types, &block)
|
|
26
|
+
session.search(*types, &block)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def remove(*objects)
|
|
30
|
+
session.remove(*objects)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def remove_all(*classes)
|
|
34
|
+
session.remove_all(*classes)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def config
|
|
38
|
+
session.config
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reset!
|
|
42
|
+
@session = nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def session
|
|
48
|
+
@session ||= ::Sunspot::Session.new
|
|
49
|
+
end
|
|
50
|
+
end
|