mwmitchell-rsolr-ext 0.5.8 → 0.5.9
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.rdoc +10 -6
- data/lib/rsolr-ext.rb +1 -1
- data/lib/rsolr-ext/request/queryable.rb +1 -1
- data/lib/rsolr-ext/response.rb +15 -24
- data/lib/rsolr-ext/response/docs.rb +96 -0
- data/lib/rsolr-ext/response/{facetable.rb → facets.rb} +22 -14
- data/rsolr-ext.gemspec +4 -6
- data/test/helper.rb +1 -19
- data/test/response_test.rb +70 -6
- metadata +4 -6
- data/lib/rsolr-ext/response/doc_ext.rb +0 -38
- data/lib/rsolr-ext/response/facet_paginator.rb +0 -24
- data/lib/rsolr-ext/response/pageable.rb +0 -30
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
=RSolr::Ext
|
2
2
|
A set of helper methods/modules to assist in building Solr queries and handling responses when using the RSolr library.
|
3
3
|
|
4
|
-
NOTE: The API for RSolr::Ext is pre 1.0. Things are
|
4
|
+
NOTE: The API for RSolr::Ext is pre 1.0. Things are changing quickly...
|
5
5
|
|
6
6
|
==Request Example
|
7
7
|
std = RSolr::Ext::Request::Standard.new
|
@@ -22,17 +22,21 @@ NOTE: The API for RSolr::Ext is pre 1.0. Things are be changing!
|
|
22
22
|
|
23
23
|
==Response Example
|
24
24
|
rsolr = RSolr.connect
|
25
|
+
|
25
26
|
raw_response = rsolr.select(:q=>'*:*)
|
26
27
|
r = RSolr::Ext::Response::Standard.new(raw_response)
|
27
28
|
|
28
|
-
r.
|
29
|
-
r.
|
30
|
-
r.
|
31
|
-
|
29
|
+
r.ok?
|
30
|
+
r.params
|
31
|
+
r.docs
|
32
|
+
r.docs.previous_page
|
33
|
+
r.docs.next_page
|
34
|
+
r.facets
|
35
|
+
|
32
36
|
===Doc Pagination
|
33
37
|
After creating a RSolr::Ext::Response object, pass-in the response.docs to the will_paginate view helper:
|
34
38
|
rsolr = RSolr.connect
|
35
39
|
raw_response = rsolr.select(:q=>'*:*)
|
36
40
|
@response = RSolr::Ext::Response::Standard.new(raw_response)
|
37
41
|
# in view:
|
38
|
-
<%= will_paginate @response.
|
42
|
+
<%= will_paginate @response.docs %>
|
data/lib/rsolr-ext.rb
CHANGED
@@ -23,7 +23,7 @@ module RSolr::Ext::Request::Queryable
|
|
23
23
|
def build_query(value, quote_string=false)
|
24
24
|
case value
|
25
25
|
when String,Symbol
|
26
|
-
|
26
|
+
quote_string ? quote(value.to_s) : value.to_s
|
27
27
|
when Array
|
28
28
|
value.collect do |v|
|
29
29
|
build_query(v, quote_string)
|
data/lib/rsolr-ext/response.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
module RSolr::Ext::Response
|
2
2
|
|
3
|
-
autoload :
|
4
|
-
autoload :
|
5
|
-
autoload :DocExt, 'rsolr-ext/response/doc_ext'
|
3
|
+
autoload :Facets, 'rsolr-ext/response/facets'
|
4
|
+
autoload :Docs, 'rsolr-ext/response/docs'
|
6
5
|
|
7
6
|
class Base < Mash
|
8
7
|
|
@@ -10,6 +9,10 @@ module RSolr::Ext::Response
|
|
10
9
|
self[:responseHeader]
|
11
10
|
end
|
12
11
|
|
12
|
+
def params
|
13
|
+
header[:params]
|
14
|
+
end
|
15
|
+
|
13
16
|
def ok?
|
14
17
|
header[:status] == 0
|
15
18
|
end
|
@@ -19,32 +22,16 @@ module RSolr::Ext::Response
|
|
19
22
|
#
|
20
23
|
class Standard < Base
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
activate_pagination!
|
25
|
+
def initialize(*args)
|
26
|
+
super(*args)
|
27
|
+
extend Docs
|
28
|
+
extend Facets
|
27
29
|
end
|
28
30
|
|
29
31
|
def response
|
30
32
|
self[:response]
|
31
33
|
end
|
32
34
|
|
33
|
-
def docs
|
34
|
-
response[:docs]
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def activate_pagination!
|
40
|
-
d = self[:response][:docs]
|
41
|
-
d.each{|dhash| dhash.extend DocExt }
|
42
|
-
d.extend Pageable
|
43
|
-
d.start = self[:responseHeader][:params][:start].to_s.to_i
|
44
|
-
d.per_page = self[:responseHeader][:params][:rows].to_s.to_i
|
45
|
-
d.total = self[:response][:numFound]
|
46
|
-
end
|
47
|
-
|
48
35
|
end
|
49
36
|
|
50
37
|
class Dismax < Standard
|
@@ -58,10 +45,14 @@ module RSolr::Ext::Response
|
|
58
45
|
# An optional rule can be used for "grepping" field names:
|
59
46
|
# field_list(/_facet$/)
|
60
47
|
def field_list(rule=nil)
|
61
|
-
|
48
|
+
fields.select do |k,v|
|
62
49
|
rule ? k =~ rule : true
|
63
50
|
end.collect{|k,v|k}
|
64
51
|
end
|
52
|
+
|
53
|
+
def fields
|
54
|
+
self[:fields]
|
55
|
+
end
|
65
56
|
|
66
57
|
end# end Luke
|
67
58
|
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module RSolr::Ext::Response::Docs
|
2
|
+
|
3
|
+
module Accessable
|
4
|
+
|
5
|
+
# Helper method to check if value/multi-values exist for a given key.
|
6
|
+
# The value can be a string, or a RegExp
|
7
|
+
# Multiple "values" can be given; only one needs to match.
|
8
|
+
#
|
9
|
+
# Example:
|
10
|
+
# doc.has?(:location_facet)
|
11
|
+
# doc.has?(:location_facet, 'Clemons')
|
12
|
+
# doc.has?(:id, 'h009', /^u/i)
|
13
|
+
def has?(k, *values)
|
14
|
+
return if self[k].nil?
|
15
|
+
return true if self.key?(k) and values.empty?
|
16
|
+
target = self[k]
|
17
|
+
if target.is_a?(Array)
|
18
|
+
values.each do |val|
|
19
|
+
return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
|
20
|
+
end
|
21
|
+
else
|
22
|
+
return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# helper
|
27
|
+
# key is the name of the field
|
28
|
+
# opts is a hash with the following valid keys:
|
29
|
+
# - :sep - a string used for joining multivalued field values
|
30
|
+
# - :default - a value to return when the key doesn't exist
|
31
|
+
# if :sep is nil and the field is a multivalued field, the array is returned
|
32
|
+
def get(key, opts={:sep=>', ', :default=>nil})
|
33
|
+
if self.key? key
|
34
|
+
val = self[key]
|
35
|
+
(val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
|
36
|
+
else
|
37
|
+
opts[:default]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
module Pageable
|
44
|
+
|
45
|
+
attr_accessor :start, :per_page, :total
|
46
|
+
|
47
|
+
# Returns the current page calculated from 'rows' and 'start'
|
48
|
+
# WillPaginate hook
|
49
|
+
def current_page
|
50
|
+
return 1 if start < 1
|
51
|
+
per_page_normalized = per_page < 1 ? 1 : per_page
|
52
|
+
@current_page ||= (start / per_page_normalized).ceil + 1
|
53
|
+
end
|
54
|
+
|
55
|
+
# Calcuates the total pages from 'numFound' and 'rows'
|
56
|
+
# WillPaginate hook
|
57
|
+
def total_pages
|
58
|
+
@total_pages ||= per_page > 0 ? (total / per_page.to_f).ceil : 1
|
59
|
+
end
|
60
|
+
|
61
|
+
# returns the previous page number or 1
|
62
|
+
# WillPaginate hook
|
63
|
+
def previous_page
|
64
|
+
@previous_page ||= (current_page > 1) ? current_page - 1 : 1
|
65
|
+
end
|
66
|
+
|
67
|
+
# returns the next page number or the last
|
68
|
+
# WillPaginate hook
|
69
|
+
def next_page
|
70
|
+
@next_page ||= (current_page == total_pages) ? total_pages : current_page+1
|
71
|
+
end
|
72
|
+
|
73
|
+
def has_next?
|
74
|
+
current_page < total_pages
|
75
|
+
end
|
76
|
+
|
77
|
+
def has_previous?
|
78
|
+
current_page > 1
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.extended(base)
|
84
|
+
d = base.response[:docs]
|
85
|
+
d.extend Pageable
|
86
|
+
d.each{|item|item.extend Accessable}
|
87
|
+
d.start = base.header[:params][:start].to_s.to_i
|
88
|
+
d.per_page = base.header[:params][:rows].to_s.to_i
|
89
|
+
d.total = base.response[:numFound].to_s.to_i
|
90
|
+
end
|
91
|
+
|
92
|
+
def docs
|
93
|
+
response[:docs]
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
module RSolr::Ext::Response::
|
1
|
+
module RSolr::Ext::Response::Facets
|
2
2
|
|
3
3
|
# represents a facet value; which is a field value and its hit count
|
4
|
-
class
|
4
|
+
class FacetItem
|
5
5
|
attr_reader :value,:hits
|
6
6
|
def initialize(value,hits)
|
7
7
|
@value,@hits=value,hits
|
@@ -9,12 +9,12 @@ module RSolr::Ext::Response::Facetable
|
|
9
9
|
end
|
10
10
|
|
11
11
|
# represents a facet; which is a field and its values
|
12
|
-
class
|
13
|
-
attr_reader :
|
14
|
-
attr_accessor :
|
15
|
-
def initialize(
|
16
|
-
@
|
17
|
-
@
|
12
|
+
class FacetField
|
13
|
+
attr_reader :name
|
14
|
+
attr_accessor :items
|
15
|
+
def initialize(name)
|
16
|
+
@name=name
|
17
|
+
@items=[]
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
@@ -25,25 +25,33 @@ module RSolr::Ext::Response::Facetable
|
|
25
25
|
def facets
|
26
26
|
# memoize!
|
27
27
|
@facets ||= (
|
28
|
-
facet_fields.
|
29
|
-
|
28
|
+
all = facet_fields.collect do |(facet_field_name,values_and_hits_list)|
|
29
|
+
facet = FacetField.new(facet_field_name)
|
30
30
|
# the values_and_hits_list is an array where a value is immediately followed by it's hit count
|
31
31
|
# so we shift off an item (the value)
|
32
32
|
while value = values_and_hits_list.shift
|
33
33
|
# and then shift off the next to get the hit value
|
34
|
-
facet.
|
34
|
+
facet.items << FacetItem.new(value, values_and_hits_list.shift)
|
35
35
|
# repeat until there are no more pairs in the values_and_hits_list array
|
36
36
|
end
|
37
|
-
|
37
|
+
facet
|
38
38
|
end
|
39
|
+
#all.extend RSolr::Ext::Response::Docs::Pageable
|
40
|
+
#all.start = header['params']['facet.offset'].to_s.to_i
|
41
|
+
#all.per_page = header['params']['facet.limit'].to_s.to_i - 1
|
42
|
+
#all.total = -1
|
43
|
+
## override the has_next? method -- when paging through facets,
|
44
|
+
## it's not possible to know how many "pages" there are
|
45
|
+
#all.instance_eval "def has_next?; #{all.size == all.per_page+1} end"
|
46
|
+
all
|
39
47
|
)
|
40
48
|
end
|
41
|
-
|
49
|
+
|
42
50
|
# pass in a facet field name and get back a Facet instance
|
43
51
|
def facet_by_field_name(name)
|
44
52
|
@facets_by_field_name ||= {}
|
45
53
|
@facets_by_field_name[name] ||= (
|
46
|
-
facets.detect{|facet|facet.
|
54
|
+
facets.detect{|facet|facet.name.to_s == name.to_s}
|
47
55
|
)
|
48
56
|
end
|
49
57
|
|
data/rsolr-ext.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "rsolr-ext"
|
3
|
-
s.version = "0.5.
|
4
|
-
s.date = "2009-03-
|
3
|
+
s.version = "0.5.9"
|
4
|
+
s.date = "2009-03-20"
|
5
5
|
s.summary = "An extension lib for RSolr"
|
6
6
|
s.email = "goodieboy@gmail.com"
|
7
7
|
s.homepage = "http://github.com/mwmitchell/rsolr_ext"
|
@@ -18,10 +18,8 @@ Gem::Specification.new do |s|
|
|
18
18
|
"lib/rsolr-ext/request/queryable.rb",
|
19
19
|
"lib/rsolr-ext/request.rb",
|
20
20
|
|
21
|
-
"lib/rsolr-ext/response/
|
22
|
-
"lib/rsolr-ext/response/
|
23
|
-
"lib/rsolr-ext/response/facetable.rb",
|
24
|
-
"lib/rsolr-ext/response/pageable.rb",
|
21
|
+
"lib/rsolr-ext/response/docs.rb",
|
22
|
+
"lib/rsolr-ext/response/facets.rb",
|
25
23
|
"lib/rsolr-ext/response.rb",
|
26
24
|
|
27
25
|
"lib/rsolr-ext.rb",
|
data/test/helper.rb
CHANGED
@@ -1,21 +1,3 @@
|
|
1
1
|
def mock_query_response
|
2
|
-
%({'responseHeader'=>{
|
3
|
-
'status'=>0,'QTime'=>43,'params'=>{
|
4
|
-
'q'=>'*:*','wt'=>'ruby','echoParams'=>'EXPLICIT'
|
5
|
-
}
|
6
|
-
},
|
7
|
-
'response'=>{
|
8
|
-
'numFound'=>26,'start'=>0,'docs'=>[
|
9
|
-
{'id'=>'SP2514N','inStock'=>true,'manu'=>'Samsung Electronics Co. Ltd.','name'=>'Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133','popularity'=>6,'price'=>92.0,'sku'=>'SP2514N','timestamp'=>'2008-11-21T17:21:55.601Z','cat'=>['electronics','hard drive'],'spell'=>['Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133'],'features'=>['7200RPM, 8MB cache, IDE Ultra ATA-133','NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor']},
|
10
|
-
{'id'=>'6H500F0','inStock'=>true,'manu'=>'Maxtor Corp.','name'=>'Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300','popularity'=>6,'price'=>350.0,'sku'=>'6H500F0','timestamp'=>'2008-11-21T17:21:55.617Z','cat'=>['electronics','hard drive'],'spell'=>['Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300'],'features'=>['SATA 3.0Gb/s, NCQ','8.5ms seek','16MB cache']},
|
11
|
-
{'id'=>'F8V7067-APL-KIT','inStock'=>false,'manu'=>'Belkin','name'=>'Belkin Mobile Power Cord for iPod w/ Dock','popularity'=>1,'price'=>19.95,'sku'=>'F8V7067-APL-KIT','timestamp'=>'2008-11-21T17:21:55.652Z','weight'=>4.0,'cat'=>['electronics','connector'],'spell'=>['Belkin Mobile Power Cord for iPod w/ Dock'],'features'=>['car power adapter, white']},
|
12
|
-
{'id'=>'IW-02','inStock'=>false,'manu'=>'Belkin','name'=>'iPod & iPod Mini USB 2.0 Cable','popularity'=>1,'price'=>11.5,'sku'=>'IW-02','timestamp'=>'2008-11-21T17:21:55.657Z','weight'=>2.0,'cat'=>['electronics','connector'],'spell'=>['iPod & iPod Mini USB 2.0 Cable'],'features'=>['car power adapter for iPod, white']},
|
13
|
-
{'id'=>'MA147LL/A','inStock'=>true,'includes'=>'earbud headphones, USB cable','manu'=>'Apple Computer Inc.','name'=>'Apple 60 GB iPod with Video Playback Black','popularity'=>10,'price'=>399.0,'sku'=>'MA147LL/A','timestamp'=>'2008-11-21T17:21:55.681Z','weight'=>5.5,'cat'=>['electronics','music'],'spell'=>['Apple 60 GB iPod with Video Playback Black'],'features'=>['iTunes, Podcasts, Audiobooks','Stores up to 15,000 songs, 25,000 photos, or 150 hours of video','2.5-inch, 320x240 color TFT LCD display with LED backlight','Up to 20 hours of battery life','Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video','Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication']},
|
14
|
-
{'id'=>'TWINX2048-3200PRO','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail','popularity'=>5,'price'=>185.0,'sku'=>'TWINX2048-3200PRO','timestamp'=>'2008-11-21T17:21:55.706Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail'],'features'=>['CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader']},
|
15
|
-
{'id'=>'VS1GB400C3','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail','popularity'=>7,'price'=>74.99,'sku'=>'VS1GB400C3','timestamp'=>'2008-11-21T17:21:55.71Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail']},
|
16
|
-
{'id'=>'VDBDB1A16','inStock'=>true,'manu'=>'A-DATA Technology Inc.','name'=>'A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM','popularity'=>5,'sku'=>'VDBDB1A16','timestamp'=>'2008-11-21T17:21:55.712Z','cat'=>['electronics','memory'],'spell'=>['A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM'],'features'=>['CAS latency 3, 2.7v']},
|
17
|
-
{'id'=>'3007WFP','inStock'=>true,'includes'=>'USB cable','manu'=>'Dell, Inc.','name'=>'Dell Widescreen UltraSharp 3007WFP','popularity'=>6,'price'=>2199.0,'sku'=>'3007WFP','timestamp'=>'2008-11-21T17:21:55.724Z','weight'=>401.6,'cat'=>['electronics','monitor'],'spell'=>['Dell Widescreen UltraSharp 3007WFP'],'features'=>['30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast']},
|
18
|
-
{'id'=>'VA902B','inStock'=>true,'manu'=>'ViewSonic Corp.','name'=>'ViewSonic VA902B - flat panel display - TFT - 19"','popularity'=>6,'price'=>279.95,'sku'=>'VA902B','timestamp'=>'2008-11-21T17:21:55.734Z','weight'=>190.4,'cat'=>['electronics','monitor'],'spell'=>['ViewSonic VA902B - flat panel display - TFT - 19"'],'features'=>['19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution']}]
|
19
|
-
}
|
20
|
-
})
|
2
|
+
%({'responseHeader'=>{'status'=>0,'QTime'=>5,'params'=>{'facet.limit'=>'10','wt'=>'ruby','rows'=>'11','facet'=>'true','facet.field'=>['manu','cat'],'echoParams'=>'EXPLICIT','q'=>'*:*','facet.sort'=>'true'}},'response'=>{'numFound'=>26,'start'=>0,'docs'=>[{'id'=>'SP2514N','inStock'=>true,'manu'=>'Samsung Electronics Co. Ltd.','name'=>'Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133','popularity'=>6,'price'=>92.0,'sku'=>'SP2514N','timestamp'=>'2009-03-20T14:42:49.795Z','cat'=>['electronics','hard drive'],'spell'=>['Samsung SpinPoint P120 SP2514N - hard drive - 250 GB - ATA-133'],'features'=>['7200RPM, 8MB cache, IDE Ultra ATA-133','NoiseGuard, SilentSeek technology, Fluid Dynamic Bearing (FDB) motor']},{'id'=>'6H500F0','inStock'=>true,'manu'=>'Maxtor Corp.','name'=>'Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300','popularity'=>6,'price'=>350.0,'sku'=>'6H500F0','timestamp'=>'2009-03-20T14:42:49.877Z','cat'=>['electronics','hard drive'],'spell'=>['Maxtor DiamondMax 11 - hard drive - 500 GB - SATA-300'],'features'=>['SATA 3.0Gb/s, NCQ','8.5ms seek','16MB cache']},{'id'=>'F8V7067-APL-KIT','inStock'=>false,'manu'=>'Belkin','name'=>'Belkin Mobile Power Cord for iPod w/ Dock','popularity'=>1,'price'=>19.95,'sku'=>'F8V7067-APL-KIT','timestamp'=>'2009-03-20T14:42:49.937Z','weight'=>4.0,'cat'=>['electronics','connector'],'spell'=>['Belkin Mobile Power Cord for iPod w/ Dock'],'features'=>['car power adapter, white']},{'id'=>'IW-02','inStock'=>false,'manu'=>'Belkin','name'=>'iPod & iPod Mini USB 2.0 Cable','popularity'=>1,'price'=>11.5,'sku'=>'IW-02','timestamp'=>'2009-03-20T14:42:49.944Z','weight'=>2.0,'cat'=>['electronics','connector'],'spell'=>['iPod & iPod Mini USB 2.0 Cable'],'features'=>['car power adapter for iPod, white']},{'id'=>'MA147LL/A','inStock'=>true,'includes'=>'earbud headphones, USB cable','manu'=>'Apple Computer Inc.','name'=>'Apple 60 GB iPod with Video Playback Black','popularity'=>10,'price'=>399.0,'sku'=>'MA147LL/A','timestamp'=>'2009-03-20T14:42:49.962Z','weight'=>5.5,'cat'=>['electronics','music'],'spell'=>['Apple 60 GB iPod with Video Playback Black'],'features'=>['iTunes, Podcasts, Audiobooks','Stores up to 15,000 songs, 25,000 photos, or 150 hours of video','2.5-inch, 320x240 color TFT LCD display with LED backlight','Up to 20 hours of battery life','Plays AAC, MP3, WAV, AIFF, Audible, Apple Lossless, H.264 video','Notes, Calendar, Phone book, Hold button, Date display, Photo wallet, Built-in games, JPEG photo playback, Upgradeable firmware, USB 2.0 compatibility, Playback speed control, Rechargeable capability, Battery level indication']},{'id'=>'TWINX2048-3200PRO','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail','popularity'=>5,'price'=>185.0,'sku'=>'TWINX2048-3200PRO','timestamp'=>'2009-03-20T14:42:49.99Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR XMS 2GB (2 x 1GB) 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) Dual Channel Kit System Memory - Retail'],'features'=>['CAS latency 2, 2-3-3-6 timing, 2.75v, unbuffered, heat-spreader']},{'id'=>'VS1GB400C3','inStock'=>true,'manu'=>'Corsair Microsystems Inc.','name'=>'CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail','popularity'=>7,'price'=>74.99,'sku'=>'VS1GB400C3','timestamp'=>'2009-03-20T14:42:50Z','cat'=>['electronics','memory'],'spell'=>['CORSAIR ValueSelect 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - Retail']},{'id'=>'VDBDB1A16','inStock'=>true,'manu'=>'A-DATA Technology Inc.','name'=>'A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM','popularity'=>5,'sku'=>'VDBDB1A16','timestamp'=>'2009-03-20T14:42:50.004Z','cat'=>['electronics','memory'],'spell'=>['A-DATA V-Series 1GB 184-Pin DDR SDRAM Unbuffered DDR 400 (PC 3200) System Memory - OEM'],'features'=>['CAS latency 3, 2.7v']},{'id'=>'3007WFP','inStock'=>true,'includes'=>'USB cable','manu'=>'Dell, Inc.','name'=>'Dell Widescreen UltraSharp 3007WFP','popularity'=>6,'price'=>2199.0,'sku'=>'3007WFP','timestamp'=>'2009-03-20T14:42:50.017Z','weight'=>401.6,'cat'=>['electronics','monitor'],'spell'=>['Dell Widescreen UltraSharp 3007WFP'],'features'=>['30" TFT active matrix LCD, 2560 x 1600, .25mm dot pitch, 700:1 contrast']},{'id'=>'VA902B','inStock'=>true,'manu'=>'ViewSonic Corp.','name'=>'ViewSonic VA902B - flat panel display - TFT - 19"','popularity'=>6,'price'=>279.95,'sku'=>'VA902B','timestamp'=>'2009-03-20T14:42:50.034Z','weight'=>190.4,'cat'=>['electronics','monitor'],'spell'=>['ViewSonic VA902B - flat panel display - TFT - 19"'],'features'=>['19" TFT active matrix LCD, 8ms response time, 1280 x 1024 native resolution']},{'id'=>'0579B002','inStock'=>true,'manu'=>'Canon Inc.','name'=>'Canon PIXMA MP500 All-In-One Photo Printer','popularity'=>6,'price'=>179.99,'sku'=>'0579B002','timestamp'=>'2009-03-20T14:42:50.062Z','weight'=>352.0,'cat'=>['electronics','multifunction printer','printer','scanner','copier'],'spell'=>['Canon PIXMA MP500 All-In-One Photo Printer'],'features'=>['Multifunction ink-jet color photo printer','Flatbed scanner, optical scan resolution of 1,200 x 2,400 dpi','2.5" color LCD preview screen','Duplex Copying','Printing speed up to 29ppm black, 19ppm color','Hi-Speed USB','memory card: CompactFlash, Micro Drive, SmartMedia, Memory Stick, Memory Stick Pro, SD Card, and MultiMediaCard']}]},'facet_counts'=>{'facet_queries'=>{},'facet_fields'=>{'manu'=>['inc',8,'apach',2,'belkin',2,'canon',2,'comput',2,'corp',2,'corsair',2,'foundat',2,'microsystem',2,'softwar',2],'cat'=>['electronics',14,'memory',3,'card',2,'connector',2,'drive',2,'graphics',2,'hard',2,'monitor',2,'search',2,'software',2]},'facet_dates'=>{}}})
|
21
3
|
end
|
data/test/response_test.rb
CHANGED
@@ -16,13 +16,13 @@ class RSolrExtResponseTest < Test::Unit::TestCase
|
|
16
16
|
r = RSolr::Ext::Response::Standard.new(raw_response)
|
17
17
|
assert r.respond_to?(:response)
|
18
18
|
assert r.ok?
|
19
|
-
assert_equal
|
20
|
-
assert_equal 'EXPLICIT', r
|
21
|
-
assert_equal 1, r
|
22
|
-
assert_equal
|
19
|
+
assert_equal 11, r.docs.size
|
20
|
+
assert_equal 'EXPLICIT', r.params[:echoParams]
|
21
|
+
assert_equal 1, r.docs.previous_page
|
22
|
+
assert_equal 2, r.docs.next_page
|
23
23
|
#
|
24
|
-
assert r
|
25
|
-
assert r.kind_of?(RSolr::Ext::Response::
|
24
|
+
assert r.kind_of?(RSolr::Ext::Response::Docs)
|
25
|
+
assert r.kind_of?(RSolr::Ext::Response::Facets)
|
26
26
|
end
|
27
27
|
|
28
28
|
test 'standard response doc ext methods' do
|
@@ -38,4 +38,68 @@ class RSolrExtResponseTest < Test::Unit::TestCase
|
|
38
38
|
assert_equal 'def', doc.get(:xyz, :default=>'def')
|
39
39
|
end
|
40
40
|
|
41
|
+
test 'Response::Standard facets' do
|
42
|
+
raw_response = eval(mock_query_response)
|
43
|
+
r = RSolr::Ext::Response::Standard.new(raw_response)
|
44
|
+
assert_equal 2, r.facets.size
|
45
|
+
|
46
|
+
field_names = r.facets.collect{|facet|facet.name}
|
47
|
+
assert field_names.include?('cat')
|
48
|
+
assert field_names.include?('manu')
|
49
|
+
|
50
|
+
first_facet = r.facets.first
|
51
|
+
assert_equal 'cat', first_facet.name
|
52
|
+
assert_equal 10, first_facet.items.size
|
53
|
+
|
54
|
+
expected = first_facet.items.collect do |item|
|
55
|
+
item.value + ' - ' + item.hits.to_s
|
56
|
+
end.join(', ')
|
57
|
+
assert_equal "electronics - 14, memory - 3, card - 2, connector - 2, drive - 2, graphics - 2, hard - 2, monitor - 2, search - 2, software - 2", expected
|
58
|
+
|
59
|
+
r.facets.each do |facet|
|
60
|
+
assert facet.respond_to?(:name)
|
61
|
+
facet.items.each do |item|
|
62
|
+
assert item.respond_to?(:value)
|
63
|
+
assert item.respond_to?(:hits)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
test 'response::standard facet_by_field_name' do
|
70
|
+
raw_response = eval(mock_query_response)
|
71
|
+
r = RSolr::Ext::Response::Standard.new(raw_response)
|
72
|
+
facet = r.facet_by_field_name('cat')
|
73
|
+
assert_equal 'cat', facet.name
|
74
|
+
end
|
75
|
+
|
76
|
+
=begin
|
77
|
+
|
78
|
+
# pagination for facets has been commented out in the response/facets module.
|
79
|
+
# ...need to think more about how this can be handled
|
80
|
+
|
81
|
+
test 'response::standard facets.paginate' do
|
82
|
+
raw_response = eval(mock_query_response)
|
83
|
+
raw_response['responseHeader']['params']['facet.offset'] = 1
|
84
|
+
raw_response['responseHeader']['params']['facet.limit'] = 2
|
85
|
+
|
86
|
+
r = RSolr::Ext::Response::Standard.new(raw_response)
|
87
|
+
|
88
|
+
assert_equal 2, r.facets.current_page
|
89
|
+
|
90
|
+
# always 1 less than facet.limit
|
91
|
+
assert_equal 1, r.facets.per_page
|
92
|
+
|
93
|
+
assert_equal 3, r.facets.next_page
|
94
|
+
|
95
|
+
assert_equal 1, r.facets.previous_page
|
96
|
+
|
97
|
+
# can't know how many pages there are with facets.... so we set it to -1
|
98
|
+
assert_equal -1, r.facets.total_pages
|
99
|
+
|
100
|
+
assert r.facets.has_next?
|
101
|
+
assert r.facets.has_previous?
|
102
|
+
end
|
103
|
+
=end
|
104
|
+
|
41
105
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mwmitchell-rsolr-ext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Mitchell
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-20 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -28,10 +28,8 @@ files:
|
|
28
28
|
- lib/rsolr-ext/mapable.rb
|
29
29
|
- lib/rsolr-ext/request/queryable.rb
|
30
30
|
- lib/rsolr-ext/request.rb
|
31
|
-
- lib/rsolr-ext/response/
|
32
|
-
- lib/rsolr-ext/response/
|
33
|
-
- lib/rsolr-ext/response/facetable.rb
|
34
|
-
- lib/rsolr-ext/response/pageable.rb
|
31
|
+
- lib/rsolr-ext/response/docs.rb
|
32
|
+
- lib/rsolr-ext/response/facets.rb
|
35
33
|
- lib/rsolr-ext/response.rb
|
36
34
|
- lib/rsolr-ext.rb
|
37
35
|
- LICENSE
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# module for adding helper methods to each solr response[:docs] object
|
2
|
-
module RSolr::Ext::Response::DocExt
|
3
|
-
|
4
|
-
# Helper method to check if value/multi-values exist for a given key.
|
5
|
-
# The value can be a string, or a RegExp
|
6
|
-
# Example:
|
7
|
-
# doc.has?(:location_facet)
|
8
|
-
# doc.has?(:location_facet, 'Clemons')
|
9
|
-
# doc.has?(:id, 'h009', /^u/i)
|
10
|
-
def has?(k, *values)
|
11
|
-
return if self[k].nil?
|
12
|
-
return true if self.key?(k) and values.empty?
|
13
|
-
target = self[k]
|
14
|
-
if target.is_a?(Array)
|
15
|
-
values.each do |val|
|
16
|
-
return target.any?{|tv| val.is_a?(Regexp) ? (tv =~ val) : (tv==val)}
|
17
|
-
end
|
18
|
-
else
|
19
|
-
return values.any? {|val| val.is_a?(Regexp) ? (target =~ val) : (target == val)}
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# helper
|
24
|
-
# key is the name of the field
|
25
|
-
# opts is a hash with the following valid keys:
|
26
|
-
# - :sep - a string used for joining multivalued field values
|
27
|
-
# - :default - a value to return when the key doesn't exist
|
28
|
-
# if :sep is nil and the field is a multivalued field, the array is returned
|
29
|
-
def get(key, opts={:sep=>', ', :default=>nil})
|
30
|
-
if self.key? key
|
31
|
-
val = self[key]
|
32
|
-
(val.is_a?(Array) and opts[:sep]) ? val.join(opts[:sep]) : val
|
33
|
-
else
|
34
|
-
opts[:default]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
class RSolr::Ext::Response::FacetPaginator
|
2
|
-
|
3
|
-
attr_reader :total, :items, :previous_offset, :next_offset
|
4
|
-
|
5
|
-
def initialize(all_facet_values, offset, limit)
|
6
|
-
offset = offset.to_s.to_i
|
7
|
-
limit = limit.to_s.to_i
|
8
|
-
total = all_facet_values.size
|
9
|
-
@items = all_facet_values.slice(0, limit-1)
|
10
|
-
@has_next = total == limit
|
11
|
-
@has_previous = offset > 0
|
12
|
-
@next_offset = offset + (limit-1)
|
13
|
-
@previous_offset = offset - (limit-1)
|
14
|
-
end
|
15
|
-
|
16
|
-
def has_next?
|
17
|
-
@has_next
|
18
|
-
end
|
19
|
-
|
20
|
-
def has_previous?
|
21
|
-
@has_previous
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module RSolr::Ext::Response::Pageable
|
2
|
-
|
3
|
-
attr_accessor :start, :per_page, :total
|
4
|
-
|
5
|
-
# Returns the current page calculated from 'rows' and 'start'
|
6
|
-
# WillPaginate hook
|
7
|
-
def current_page
|
8
|
-
return 1 if start < 1
|
9
|
-
@current_page ||= (start / per_page).ceil + 1
|
10
|
-
end
|
11
|
-
|
12
|
-
# Calcuates the total pages from 'numFound' and 'rows'
|
13
|
-
# WillPaginate hook
|
14
|
-
def total_pages
|
15
|
-
@total_pages ||= per_page > 0 ? (total / per_page.to_f).ceil : 1
|
16
|
-
end
|
17
|
-
|
18
|
-
# returns the previous page number or 1
|
19
|
-
# WillPaginate hook
|
20
|
-
def previous_page
|
21
|
-
@previous_page ||= (current_page > 1) ? current_page - 1 : 1
|
22
|
-
end
|
23
|
-
|
24
|
-
# returns the next page number or the last
|
25
|
-
# WillPaginate hook
|
26
|
-
def next_page
|
27
|
-
@next_page ||= (current_page < total_pages) ? current_page + 1 : total_pages
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|