forked from rubygems/rubygems.org
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathelastic_searcher.rb
106 lines (95 loc) · 2.9 KB
/
elastic_searcher.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
class ElasticSearcher
def initialize(query, page: 1, api: false)
@query = query
@page = page
@api = api
end
def search
result = Rubygem.__elasticsearch__.search(search_definition).page(@page)
result.response # ES query is triggered here to allow fallback. avoids lazy loading done in the view
@api ? result.map(&:_source) : [nil, result]
rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Elasticsearch::Transport::Transport::Error => err
result = Rubygem.legacy_search(@query).page(@page)
@api ? result : [error_msg(err), result]
end
private
def search_definition # rubocop:disable Metrics/MethodLength
query_str = @query
source_array = @api ? api_source : ui_source
Elasticsearch::DSL::Search.search do
query do
function_score do
query do
bool do
# Main query, search in name, summary, description
should do
query_string do
query query_str
fields ['name^5', 'summary^3', 'description']
default_operator 'and'
end
end
minimum_should_match 1
# only return gems that are not yanked
filter { term yanked: false }
end
end
# Boost the score based on number of downloads
functions << { field_value_factor: { field: :downloads, modifier: :log1p } }
end
end
aggregation :matched_field do
filters do
filters name: { terms: { name: [query_str] } },
summary: { terms: { 'summary.raw' => [query_str] } },
description: { terms: { 'description.raw' => [query_str] } }
end
end
aggregation :date_range do
date_range do
field 'updated'
ranges [{ from: 'now-7d/d', to: 'now' }, { from: 'now-30d/d', to: 'now' }]
end
end
source source_array
# Return suggestions unless there's no query from the user
suggest :suggest_name, text: query_str, term: { field: 'name.suggest', suggest_mode: 'always' } if query_str.present?
end
end
def error_msg(error)
if error.is_a? Elasticsearch::Transport::Transport::Errors::BadRequest
"Failed to parse: '#{@query}'. Falling back to legacy search."
else
Honeybadger.notify(error)
"Advanced search is currently unavailable. Falling back to legacy search."
end
end
def api_source
%w[name
downloads
version
version_downloads
platform
authors
info
licenses
metadata
sha
project_uri
gem_uri
homepage_uri
wiki_uri
documentation_uri
mailing_list_uri
source_code_uri
bug_tracker_uri
changelog_uri]
end
def ui_source
%w[name
summary
description
downloads
version]
end
end