sunspot_stats 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +59 -0
- data/Rakefile +2 -0
- data/lib/dsl/field_query.rb +22 -0
- data/lib/edismax.rb +20 -0
- data/lib/query/field_stat.rb +31 -0
- data/lib/query/stat_query.rb +12 -0
- data/lib/search/stat_facet.rb +46 -0
- data/lib/search/stat_row.rb +28 -0
- data/lib/search/stat_search.rb +57 -0
- data/lib/sunspot_stats.rb +15 -0
- data/lib/sunspot_stats/version.rb +3 -0
- data/sunspot_stats.gemspec +27 -0
- metadata +108 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Duccio Giovannelli
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Sunspot Stats
|
2
|
+
|
3
|
+
Sunspot is a Ruby library for expressive, powerful interaction with the Solr search engine. I use the latest version [2.0.0.pre.120417](https://rubygems.org/gems/sunspot/versions/2.0.0.pre.120417) but i need the statsComponent in order to get the sum on a given indexed field.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sunspot_stats'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sunspot_stats
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
The statComponent let you to have *min*, *max*, *count*, *missing*, *sum*, *sumOfsquare*, *mean* and *stdev*.
|
22
|
+
|
23
|
+
### An usage example
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
Model.search do
|
27
|
+
#Filters
|
28
|
+
...
|
29
|
+
#Facets
|
30
|
+
...
|
31
|
+
#Stats
|
32
|
+
stat(:your_field, :facet => :your_facet_filed, :type => "min")
|
33
|
+
...
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
37
|
+
**:facet** and **:type** are optional the default type is the "sum" (you can pass: *min*, *max*, *count*, *missing*, *sum*, *sumOfsquare*, *mean*, *stdev* as string)
|
38
|
+
|
39
|
+
Remember to stats on a non multi valued field and update to the solr3.6, because the solr3.5 has a bug with stats.
|
40
|
+
|
41
|
+
the Sunspot::SearchStatRow has the method *stat_field* and the *value*.
|
42
|
+
|
43
|
+
If you enable faceting on stats the stat_field is the facet and the value is the type defined.
|
44
|
+
|
45
|
+
[Upgrade solr in sunspot](https://github.com/sunspot/sunspot/wiki/Upgrading-sunspot_solr-Solr-Instance)
|
46
|
+
|
47
|
+
### Boolean Searches
|
48
|
+
|
49
|
+
Usually Suspot use the dismax for searches, here we extend to edismax to manage also boolean logic searches
|
50
|
+
|
51
|
+
a OR (b AND c) works.
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
1. Fork it
|
56
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
57
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
58
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
59
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module DSL
|
3
|
+
#
|
4
|
+
# Provides an API for areas of the query DSL that operate on specific
|
5
|
+
# fields. This functionality is provided by the query DSL and the dynamic
|
6
|
+
# query DSL.
|
7
|
+
#
|
8
|
+
class FieldQuery < Scope
|
9
|
+
def initialize(search, query, setup) #:nodoc:
|
10
|
+
@search, @query = search, query
|
11
|
+
super(query.scope, setup)
|
12
|
+
end
|
13
|
+
|
14
|
+
def stat(field_name, options = {})
|
15
|
+
field = @setup.field(field_name)
|
16
|
+
options[:facet] = @setup.field(options[:facet]) if options[:facet].present?
|
17
|
+
stat = @query.add_stat(Sunspot::Query::FieldStat.new(field, options))
|
18
|
+
@search.add_field_stat(field, options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/edismax.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
OriginalDismax = Sunspot::Query::Dismax
|
2
|
+
|
3
|
+
class PatchedDismax < OriginalDismax
|
4
|
+
|
5
|
+
def to_params
|
6
|
+
params = super
|
7
|
+
params[:defType] = 'edismax'
|
8
|
+
params
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_subquery
|
12
|
+
query = super
|
13
|
+
query = query.sub '{!dismax', '{!edismax'
|
14
|
+
query
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
Sunspot::Query.send :remove_const, :Dismax
|
20
|
+
Sunspot::Query::Dismax = PatchedDismax
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Query
|
3
|
+
#
|
4
|
+
# A FieldStat stats by the unique values of a given field.
|
5
|
+
#
|
6
|
+
class FieldStat
|
7
|
+
|
8
|
+
def initialize(field, options = {})
|
9
|
+
if field.multiple?
|
10
|
+
raise(ArgumentError, "#{field.name} cannot be used for stats because it is a multiple-value field")
|
11
|
+
end
|
12
|
+
@field = field
|
13
|
+
@options = options
|
14
|
+
@sort = SortComposite.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_sort(sort)
|
18
|
+
@sort << sort
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_params
|
22
|
+
params = {
|
23
|
+
:stats => 'true',
|
24
|
+
:"stats.field" => @field.indexed_name
|
25
|
+
}
|
26
|
+
params.merge!({:"stats.facet" => @options[:facet].indexed_name}) if @options[:facet].present?
|
27
|
+
params
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Search
|
3
|
+
class StatFacet
|
4
|
+
|
5
|
+
def initialize(field, search, options)
|
6
|
+
@field, @search, @options = field, search, options
|
7
|
+
end
|
8
|
+
|
9
|
+
def field_name
|
10
|
+
@field.name
|
11
|
+
end
|
12
|
+
|
13
|
+
def rows
|
14
|
+
@options[:type] ||= "sum"
|
15
|
+
@sort = false
|
16
|
+
@rows ||=
|
17
|
+
begin
|
18
|
+
if !@search.stat_response['stats_fields'].nil?
|
19
|
+
if @options[:facet].present?
|
20
|
+
stat = @search.stat_response['stats_fields'][@field.indexed_name]
|
21
|
+
data = stat.nil? ? [] : stat['facets'][@options[:facet].indexed_name]
|
22
|
+
@sort = true
|
23
|
+
else
|
24
|
+
data = @search.stat_response['stats_fields'].to_a
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rows = []
|
29
|
+
|
30
|
+
data.collect do |stat, value|
|
31
|
+
rows << StatRow.new(stat, value[@options[:type]], self)
|
32
|
+
end
|
33
|
+
|
34
|
+
if @options[:sort] == :type
|
35
|
+
rows.sort! { |lrow, rrow| rrow.count <=> lrow.count }
|
36
|
+
else
|
37
|
+
rows.sort! { |lrow, rrow| lrow.stat_field <=> rrow.stat_field }
|
38
|
+
end if @sort
|
39
|
+
rows
|
40
|
+
rescue Exception => e
|
41
|
+
puts "Error: #{e}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Sunspot
|
2
|
+
module Search
|
3
|
+
class StatRow
|
4
|
+
attr_reader :stat_field, :value
|
5
|
+
attr_writer :instance #:nodoc:
|
6
|
+
|
7
|
+
def initialize(stat_field, value, stat) #:nodoc:
|
8
|
+
@stat_field, @value, @stat = stat_field, value, stat
|
9
|
+
end
|
10
|
+
|
11
|
+
#
|
12
|
+
# Return the instance referenced by this stat row. Only valid for field
|
13
|
+
# stats whose fields are defined with the :references key.
|
14
|
+
#
|
15
|
+
|
16
|
+
def instance
|
17
|
+
if !defined?(@instance)
|
18
|
+
@stat.populate_instances
|
19
|
+
end
|
20
|
+
@instance
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
"<Sunspot::Search::StatRow:#{stat_field.inspect} (#{value})>"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'sunspot/search/paginated_collection'
|
2
|
+
require 'sunspot/search/hit_enumerable'
|
3
|
+
|
4
|
+
module Sunspot
|
5
|
+
module Search #:nodoc:
|
6
|
+
|
7
|
+
#
|
8
|
+
# This class encapsulates the results of a Solr search. It provides access
|
9
|
+
# to search results, total result count, facets, and pagination information.
|
10
|
+
# Instances of Search are returned by the Sunspot.search and
|
11
|
+
# Sunspot.new_search methods.
|
12
|
+
#
|
13
|
+
class AbstractSearch
|
14
|
+
#
|
15
|
+
# Retrieve all facet objects defined for this search, in order they were
|
16
|
+
# defined. To retrieve an individual facet by name, use #facet()
|
17
|
+
#
|
18
|
+
attr_reader :stats
|
19
|
+
|
20
|
+
def initialize(connection, setup, query, configuration) #:nodoc:
|
21
|
+
@connection, @setup, @query = connection, setup, query
|
22
|
+
@query.paginate(1, configuration.pagination.default_per_page)
|
23
|
+
|
24
|
+
@stats = []
|
25
|
+
@stats_by_name = {}
|
26
|
+
|
27
|
+
@facets = []
|
28
|
+
@facets_by_name = {}
|
29
|
+
|
30
|
+
@groups_by_name = {}
|
31
|
+
@groups = []
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def stat(name)
|
36
|
+
if name
|
37
|
+
@stats_by_name[name.to_sym]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def stat_response #:nodoc:
|
42
|
+
@solr_result['stats']
|
43
|
+
end
|
44
|
+
|
45
|
+
def add_field_stat(field, options = {}) #:nodoc:
|
46
|
+
name = (options[:name] || field.name)
|
47
|
+
add_stat(name, StatFacet.new(field, self, options))
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_stat(name, stat)
|
51
|
+
@stats << stat
|
52
|
+
@stats_by_name[name.to_sym] = stat
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "sunspot_stats/version"
|
2
|
+
|
3
|
+
%w(field_query).each do |file|
|
4
|
+
require File.join(File.dirname(__FILE__), "dsl", file)
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
%w(stat_search stat_row stat_facet).each do |file|
|
9
|
+
require File.join(File.dirname(__FILE__), "search", file)
|
10
|
+
end
|
11
|
+
|
12
|
+
%w(stat_query field_stat).each do |file|
|
13
|
+
require(File.join(File.dirname(__FILE__), 'query', file))
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sunspot_stats/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["duccio giovannelli"]
|
6
|
+
gem.email = ["giovannelli@extendi.it"]
|
7
|
+
gem.description = <<-TEXT
|
8
|
+
Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. This gem extend sunspot adding the
|
9
|
+
statsComponent feature, which returns simple statistics for indexed numeric fields within the DocSet. Usually Suspot use the dismax
|
10
|
+
for searches, here we extend to edismax to manage also boolean logic searches.
|
11
|
+
TEXT
|
12
|
+
gem.summary = "Added the statsComponent to sunspot"
|
13
|
+
gem.homepage = "https://github.com/giovannelli/sunspot_stats"
|
14
|
+
gem.files = `git ls-files`.split($\)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.name = "sunspot_stats"
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.version = SunspotStats::VERSION
|
20
|
+
|
21
|
+
gem.add_dependency "sunspot", "~> 2.0.0.pre.120417"
|
22
|
+
gem.add_development_dependency "rspec"
|
23
|
+
|
24
|
+
gem.rdoc_options << '--webcvs=http://github.com/giovannelli/sunspot_stats/tree/master/%s' <<
|
25
|
+
'--title' << 'Sunspot Stat - StatsComponent for sunspot - API Documentation' <<
|
26
|
+
'--main' << 'README.rdoc'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sunspot_stats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- duccio giovannelli
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-07-14 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sunspot
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 0
|
30
|
+
- 0
|
31
|
+
- pre
|
32
|
+
- 120417
|
33
|
+
version: 2.0.0.pre.120417
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: " Sunspot is a library providing a powerful, all-ruby API for the Solr search engine. This gem extend sunspot adding the \n statsComponent feature, which returns simple statistics for indexed numeric fields within the DocSet. Usually Suspot use the dismax\n for searches, here we extend to edismax to manage also boolean logic searches.\n"
|
49
|
+
email:
|
50
|
+
- giovannelli@extendi.it
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- Gemfile
|
60
|
+
- LICENSE
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- lib/dsl/field_query.rb
|
64
|
+
- lib/edismax.rb
|
65
|
+
- lib/query/field_stat.rb
|
66
|
+
- lib/query/stat_query.rb
|
67
|
+
- lib/search/stat_facet.rb
|
68
|
+
- lib/search/stat_row.rb
|
69
|
+
- lib/search/stat_search.rb
|
70
|
+
- lib/sunspot_stats.rb
|
71
|
+
- lib/sunspot_stats/version.rb
|
72
|
+
- sunspot_stats.gemspec
|
73
|
+
has_rdoc: true
|
74
|
+
homepage: https://github.com/giovannelli/sunspot_stats
|
75
|
+
licenses: []
|
76
|
+
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options:
|
79
|
+
- --webcvs=http://github.com/giovannelli/sunspot_stats/tree/master/%s
|
80
|
+
- --title
|
81
|
+
- Sunspot Stat - StatsComponent for sunspot - API Documentation
|
82
|
+
- --main
|
83
|
+
- README.rdoc
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
requirements: []
|
101
|
+
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 1.3.6
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: Added the statsComponent to sunspot
|
107
|
+
test_files: []
|
108
|
+
|