This repository has been archived by the owner on May 7, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfacets.rb
252 lines (204 loc) · 7.34 KB
/
facets.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# frozen_string_literal: true
require 'ostruct'
module Harvard::LibraryCloud::Facets
include ApplicationHelper
# represents a facet value; which is a field value and its hit count
class FacetItem < OpenStruct
def initialize *args
options = args.extract_options!
# Backwards-compat method signature
value = args.shift
hits = args.shift
options[:value] = value if value
options[:hits] = hits if hits
super(options)
end
def label
super || value
end
def as_json(props = nil)
table.as_json(props)
end
end
# represents a facet; which is a field and its values
class FacetField
attr_reader :name, :items
def initialize name, items, options = {}
@name = name
@items = items
@options = options
end
def limit
@options[:limit] || solr_default_limit
end
def sort
@options[:sort] || solr_default_sort
end
def offset
@options[:offset] || solr_default_offset
end
def prefix
@options[:prefix] || solr_default_prefix
end
def index?
sort == 'index'
end
def count?
sort == 'count'
end
private
# Per https://wiki.apache.org/solr/SimpleFacetParameters#facet.limit
def solr_default_limit
100
end
# Per https://wiki.apache.org/solr/SimpleFacetParameters#facet.sort
def solr_default_sort
if limit > 0
'count'
else
'index'
end
end
# Per https://wiki.apache.org/solr/SimpleFacetParameters#facet.offset
def solr_default_offset
0
end
def solr_default_prefix
nil
end
end
##
# Get all the Solr facet data (fields, queries, pivots) as a hash keyed by
# both the Solr field name and/or by the blacklight field name
def aggregations
@aggregations ||= {}.merge(facet_field_aggregations).merge(facet_query_aggregations).merge(facet_pivot_aggregations)
end
def facet_counts
@facet_counts ||= self['facets'] || {}
end
# Returns the hash of all the facet_fields (ie: { 'instock_b' => ['true', 123, 'false', 20] }
def facet_fields
@facet_fields ||= begin
val = {}
if facet_counts['facetField'].kind_of?(Array)
facet_counts['facetField'].each do |f|
val[f[:facetName]] = []
hash_as_list(f[:facet]).each do |v|
val[f[:facetName]] << v[:term]
val[f[:facetName]] << v[:count]
end if f[:facet]
end if facet_counts and facet_counts['facetField']
else
val[facet_counts['facetField'][:facetName]] = []
hash_as_list(facet_counts['facetField'][:facet]).each do |v|
val[facet_counts['facetField'][:facetName]] << v[:term]
val[facet_counts['facetField'][:facetName]] << v[:count]
end if facet_counts['facetField'][:facet]
end
val
end
end
# Returns all of the facet queries
def facet_queries
@facet_queries ||= facet_counts['facet_queries'] || {}
end
# Returns all of the facet queries
def facet_pivot
@facet_pivot ||= facet_counts['facet_pivot'] || {}
end
private
##
# Convert Solr responses of various json.nl flavors to
def list_as_hash solr_list
# map
if solr_list.values.first.is_a? Hash
solr_list
else
solr_list.each_with_object({}) do |(key, values), hash|
hash[key] = if values.first.is_a? Array
# arrarr
Hash[values]
else
# flat
Hash[values.each_slice(2).to_a]
end
end
end
end
##
# Convert Solr's facet_field response into
# a hash of Blacklight::Solr::Response::Facet::FacetField objects
def facet_field_aggregations
list_as_hash(facet_fields).each_with_object({}) do |(facet_field_name, values), hash|
items = values.map do |value, hits|
i = FacetItem.new(value: value, hits: hits)
# solr facet.missing serialization
if value.nil?
i.label = I18n.t(:"blacklight.search.fields.facet.missing.#{facet_field_name}", default: [:"blacklight.search.facets.missing"])
i.fq = "-#{facet_field_name}:[* TO *]"
end
i
end
options = facet_field_aggregation_options(facet_field_name)
hash[facet_field_name] = FacetField.new(facet_field_name,
items,
options)
# alias all the possible blacklight config names..
blacklight_config.facet_fields.select { |k,v| v.field == facet_field_name }.each do |key,_|
hash[key] = hash[facet_field_name]
end if blacklight_config and !blacklight_config.facet_fields[facet_field_name]
end
end
def facet_field_aggregation_options(facet_field_name)
options = {}
options[:sort] = (params[:"f.#{facet_field_name}.facet.sort"] || params[:'facet.sort'])
if params[:"f.#{facet_field_name}.facet.limit"] || params[:"facet.limit"]
options[:limit] = (params[:"f.#{facet_field_name}.facet.limit"] || params[:"facet.limit"]).to_i
end
if params[:"f.#{facet_field_name}.facet.offset"] || params[:'facet.offset']
options[:offset] = (params[:"f.#{facet_field_name}.facet.offset"] || params[:'facet.offset']).to_i
end
if params[:"f.#{facet_field_name}.facet.prefix"] || params[:'facet.prefix']
options[:prefix] = (params[:"f.#{facet_field_name}.facet.prefix"] || params[:'facet.prefix'])
end
options
end
##
# Aggregate Solr's facet_query response into the virtual facet fields defined
# in the blacklight configuration
def facet_query_aggregations
return {} unless blacklight_config
blacklight_config.facet_fields.select { |k,v| v.query }.each_with_object({}) do |(field_name, facet_field), hash|
salient_facet_queries = facet_field.query.map { |k, x| x[:fq] }
items = facet_queries.select { |k,v| salient_facet_queries.include?(k) }.reject { |value, hits| hits.zero? }.map do |value,hits|
salient_fields = facet_field.query.select { |key, val| val[:fq] == value }
key = ((salient_fields.keys if salient_fields.respond_to? :keys) || salient_fields.first).first
Blacklight::Solr::Response::Facets::FacetItem.new(value: key, hits: hits, label: facet_field.query[key][:label])
end
hash[field_name] = Blacklight::Solr::Response::Facets::FacetField.new field_name, items
end
end
##
# Convert Solr's facet_pivot response into
# a hash of Blacklight::Solr::Response::Facet::FacetField objects
def facet_pivot_aggregations
facet_pivot.each_with_object({}) do |(field_name, values), hash|
next unless blacklight_config and !blacklight_config.facet_fields[field_name]
items = values.map do |lst|
construct_pivot_field(lst)
end
# alias all the possible blacklight config names..
blacklight_config.facet_fields.select { |k,v| v.pivot and v.pivot.join(",") == field_name }.each do |key, _|
hash[key] = Blacklight::Solr::Response::Facets::FacetField.new key, items
end
end
end
##
# Recursively parse the pivot facet response to build up the full pivot tree
def construct_pivot_field lst, parent_fq = {}
items = Array(lst[:pivot]).map do |i|
construct_pivot_field(i, parent_fq.merge({ lst[:field] => lst[:value] }))
end
Blacklight::Solr::Response::Facets::FacetItem.new(value: lst[:value], hits: lst[:count], field: lst[:field], items: items, fq: parent_fq)
end
end # end Facets