search.rb
4.62 KB
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
module Searchkick
# can't check mapping for conversions since the new index may not be built
module Search
def index_types
Hash[ (((Product.index.mapping || {})["product"] || {})["properties"] || {}).map{|k, v| [k, v["type"]] } ].reject{|k, v| k == "conversions" || k[0] == "_" }
end
def search(term, options = {})
fields = options[:fields] || ["_all"]
operator = options[:partial] ? "or" : "and"
tire.search do
query do
boolean do
must do
dis_max do
query do
match fields, term, boost: 10, operator: operator, analyzer: "searchkick_search"
end
query do
match fields, term, boost: 10, operator: operator, analyzer: "searchkick_search2"
end
query do
match fields, term, use_dis_max: false, fuzziness: 0.7, max_expansions: 1, prefix_length: 1, operator: operator, analyzer: "searchkick_search"
end
query do
match fields, term, use_dis_max: false, fuzziness: 0.7, max_expansions: 1, prefix_length: 1, operator: operator, analyzer: "searchkick_search2"
end
end
end
if options[:conversions]
should do
nested path: "conversions", score_mode: "total" do
query do
custom_score script: "log(doc['count'].value)" do
match "query", term
end
end
end
end
end
end
end
size options[:limit] || 100000 # huge number
from options[:offset] if options[:offset]
explain options[:explain] if options[:explain]
# order
if options[:order]
sort do
options[:order].each do |k, v|
by k, v
end
end
end
# where
# TODO expand or
where_filters =
proc do |where|
filters = []
(where || {}).each do |field, value|
if field == :or
value.each do |or_clause|
filters << {or: or_clause.map{|or_statement| {term: or_statement} }}
end
else
# expand ranges
if value.is_a?(Range)
value = {gte: value.first, (value.exclude_end? ? :lt : :lte) => value.last}
end
if value.is_a?(Array) # in query
filters << {terms: {field => value}}
elsif value.is_a?(Hash)
value.each do |op, op_value|
if op == :not # not equal
if op_value.is_a?(Array)
filters << {not: {terms: {field => op_value}}}
else
filters << {not: {term: {field => op_value}}}
end
else
range_query =
case op
when :gt
{from: op_value, include_lower: false}
when :gte
{from: op_value, include_lower: true}
when :lt
{to: op_value, include_upper: false}
when :lte
{to: op_value, include_upper: true}
else
raise "Unknown where operator"
end
filters << {range: {field => range_query}}
end
end
else
filters << {term: {field => value}}
end
end
end
filters
end
where_filters.call(options[:where]).each do |f|
type, value = f.first
filter type, value
end
# facets
if options[:facets]
facets = options[:facets] || {}
if facets.is_a?(Array) # convert to more advanced syntax
facets = Hash[ facets.map{|f| [f, {}] } ]
end
facets.each do |field, facet_options|
facet_filters = where_filters.call(facet_options[:where])
facet field do
terms field
if facet_filters.size == 1
type, value = facet_filters.first.first
facet_filter type, value
elsif facet_filters.size > 1
facet_filter :and, *facet_filters
end
end
end
end
end
end
end
end