forked from sunspot/sunspot
/
hit.rb
141 lines (129 loc) · 4.34 KB
/
hit.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
module Sunspot
module Search
#
# Hit objects represent the raw information returned by Solr for a single
# document. As well as the primary key and class name, hit objects give
# access to stored field values, keyword relevance score, and geographical
# distance (for geographical search).
#
class Hit
SPECIAL_KEYS = Set.new(%w(id type score)) #:nodoc:
#
# Primary key of object associated with this hit, as string.
#
attr_reader :primary_key
#
# Class name of object associated with this hit, as string.
#
attr_reader :class_name
#
# Keyword relevance score associated with this result. Nil if this hit
# is not from a keyword search.
#
attr_reader :score
#
# For geographical searches, this is the distance between the search
# centerpoint and the document's location. Otherwise, it's nil.
#
attr_reader :distance
attr_writer :result #:nodoc:
def initialize(raw_hit, highlights, distance, search) #:nodoc:
@class_name, @primary_key = *raw_hit['id'].match(/([^ ]+) (.+)/)[1..2]
@score = raw_hit['score']
@distance = distance
@search = search
@stored_values = raw_hit
@stored_cache = {}
@highlights = highlights
end
#
# Returns all highlights for this hit when called without parameters.
# When a field_name is provided, returns only the highlight for this field.
#
def highlights(field_name = nil)
if field_name.nil?
highlights_cache.values.flatten
else
highlights_cache[field_name.to_sym]
end || []
end
#
# Return the first highlight found for a given field, or nil if there is
# none.
#
def highlight(field_name)
highlights(field_name).first
end
#
# Retrieve stored field value. For any attribute field configured with
# :stored => true, the Hit object will contain the stored value for
# that field. The value of this field will be typecast according to the
# type of the field.
#
# ==== Parameters
#
# field_name<Symbol>::
# The name of the field for which to retrieve the stored value.
# dynamic_field_name<Symbol>::
# If you want to access a stored dynamic field, this should be the
# dynamic component of the field name.
#
def stored(field_name, dynamic_field_name = nil)
field_key =
if dynamic_field_name
[field_name.to_sym, dynamic_field_name.to_sym]
else
field_name.to_sym
end
return @stored_cache[field_key] if @stored_cache.has_key?(field_key)
@stored_cache[field_key] = stored_value(field_name, dynamic_field_name)
end
#
# Retrieve the instance associated with this hit. This is lazy-loaded, but
# the first time it is called on any hit, all the hits for the search will
# load their instances using the adapter's #load_all method.
#
def result
return @result if defined?(@result)
@search.populate_hits
@result
end
alias_method :instance, :result
def inspect #:nodoc:
"#<Sunspot::Search::Hit:#{@class_name} #{@primary_key}>"
end
private
def setup
@setup ||= Sunspot::Setup.for(Util.full_const_get(@class_name))
end
def highlights_cache
@highlights_cache ||=
begin
cache = {}
if @highlights
@highlights.each_pair do |indexed_field_name, highlight_strings|
field_name = indexed_field_name.sub(/_[a-z]+$/, '').to_sym
cache[field_name] = highlight_strings.map do |highlight_string|
Highlight.new(field_name, highlight_string)
end
end
end
cache
end
end
def stored_value(field_name, dynamic_field_name)
setup.stored_fields(field_name, dynamic_field_name).each do |field|
if value = @stored_values[field.indexed_name]
case value
when Array
return value.map { |item| field.cast(item) }
else
return field.cast(value)
end
end
end
nil
end
end
end
end