Commit e16d0e8c31a79f8aa309f52e14c6fb20d57b181e
1 parent
aedd0f8e
Exists in
elasticsearch_sort
Refactored controller and searching by api
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com>
Showing
15 changed files
with
268 additions
and
25 deletions
Show diff stats
plugins/elasticsearch/controllers/elasticsearch_plugin_controller.rb
@@ -12,8 +12,27 @@ class ElasticsearchPluginController < ApplicationController | @@ -12,8 +12,27 @@ class ElasticsearchPluginController < ApplicationController | ||
12 | def search | 12 | def search |
13 | define_searchable_types | 13 | define_searchable_types |
14 | define_search_fields_types | 14 | define_search_fields_types |
15 | + define_results | ||
16 | + end | ||
17 | + | ||
18 | + def define_results | ||
19 | + @query = params[:query] | ||
20 | + @results = process_results | ||
21 | + end | ||
15 | 22 | ||
16 | - process_results | 23 | + def define_searchable_types |
24 | + @searchable_types = ElasticsearchHelper::searchable_types | ||
25 | + @selected_type = (params[:selected_type]|| :all ).to_sym | ||
17 | end | 26 | end |
18 | 27 | ||
28 | + def define_search_fields_types | ||
29 | + @search_filter_types = ElasticsearchHelper::search_filters | ||
30 | + @selected_filter_field = (params[:selected_filter_field] || ElasticsearchHelper::search_filters.keys.first).to_sym | ||
31 | + end | ||
32 | + | ||
33 | + private | ||
34 | + | ||
35 | +# def permit_params | ||
36 | +# params.require(:per_page, :query) | ||
37 | +# end | ||
19 | end | 38 | end |
@@ -0,0 +1,91 @@ | @@ -0,0 +1,91 @@ | ||
1 | +module ElasticsearchHelper | ||
2 | + | ||
3 | + def self.searchable_types | ||
4 | + { | ||
5 | + :all => { label: _("All Results")}, | ||
6 | + :community => { label: _("Communities")}, | ||
7 | + :event => { label: _("Events")}, | ||
8 | + :person => { label: _("People")} | ||
9 | + } | ||
10 | + end | ||
11 | + | ||
12 | + def self.search_filters | ||
13 | + { | ||
14 | + :lexical => { label: _("Alphabetical Order")}, | ||
15 | + :recent => { label: _("More Recent Order")}, | ||
16 | + :access => { label: _("More accessed")} | ||
17 | + } | ||
18 | + end | ||
19 | + | ||
20 | + def fields_from_model | ||
21 | + klass::SEARCHABLE_FIELDS.map do |key, value| | ||
22 | + if value[:weight] | ||
23 | + "#{key}^#{value[:weight]}" | ||
24 | + else | ||
25 | + "#{key}" | ||
26 | + end | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + def get_query text, klass=nil | ||
31 | + query = {} | ||
32 | + unless text.blank? | ||
33 | + text = text.downcase | ||
34 | + query = { | ||
35 | + query: { | ||
36 | + match_all: { | ||
37 | + } | ||
38 | + }, | ||
39 | + filter: { | ||
40 | + regexp: { | ||
41 | + name: { | ||
42 | + value: ".*" + text + ".*" } | ||
43 | + } | ||
44 | + }, | ||
45 | + suggest: { | ||
46 | + autocomplete: { | ||
47 | + text: text, | ||
48 | + term: { | ||
49 | + field: "name", | ||
50 | + suggest_mode: "always" | ||
51 | + } | ||
52 | + } | ||
53 | + } | ||
54 | + | ||
55 | + } | ||
56 | + end | ||
57 | + query | ||
58 | + end | ||
59 | + | ||
60 | + def process_results | ||
61 | + selected_type = (params[:selected_type]|| :all).to_sym | ||
62 | + if selected_type == :all | ||
63 | + search_from_all_models | ||
64 | + else | ||
65 | + search_from_model selected_type | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
69 | + def search_from_all_models | ||
70 | + models = [] | ||
71 | + query = get_query params[:query] | ||
72 | + | ||
73 | + ElasticsearchHelper::searchable_types.keys.each {| model | models.append( model.to_s.classify.constantize) if model != :all } | ||
74 | + Elasticsearch::Model.search(query, models, size: default_per_page(params[:per_page])).page(params[:page]).records | ||
75 | + end | ||
76 | + | ||
77 | + def search_from_model model | ||
78 | + begin | ||
79 | + klass = model.to_s.classify.constantize | ||
80 | + query = get_query params[:query], klass | ||
81 | + klass.search(query, size: default_per_page(params[:per_page])).page(params[:page]).records | ||
82 | + rescue | ||
83 | + [] | ||
84 | + end | ||
85 | + end | ||
86 | + | ||
87 | + def default_per_page per_page | ||
88 | + per_page ||= 10 | ||
89 | + end | ||
90 | + | ||
91 | +end |
plugins/elasticsearch/lib/elasticsearch_plugin/api.rb
1 | require_relative '../../helpers/elasticsearch_helper' | 1 | require_relative '../../helpers/elasticsearch_helper' |
2 | - | 2 | +require_relative 'entities' |
3 | 3 | ||
4 | class ElasticsearchPlugin::API < Grape::API | 4 | class ElasticsearchPlugin::API < Grape::API |
5 | include Api::Helpers | 5 | include Api::Helpers |
6 | + helpers ElasticsearchHelper | ||
6 | 7 | ||
7 | resource :search do | 8 | resource :search do |
8 | get do | 9 | get do |
9 | - present target, :with => Api::Entities::Person | 10 | + target = process_results |
11 | + present target, | ||
12 | + :with => Elasticsearch::Entities::Result, | ||
13 | + :types => ElasticsearchHelper.searchable_types.except(:all).keys.map { |key| key.to_s.classify } | ||
10 | end | 14 | end |
11 | 15 | ||
12 | get 'types' do | 16 | get 'types' do |
13 | - types = {types: ElasticsearchHelper::SEARCHABLE_TYPES.stringify_keys.keys} | 17 | + types = {types: ElasticsearchHelper::searchable_types.stringify_keys.keys} |
14 | present types, with: Grape::Presenters::Presenter | 18 | present types, with: Grape::Presenters::Presenter |
15 | end | 19 | end |
16 | 20 |
plugins/elasticsearch/lib/elasticsearch_plugin/entities.rb
0 → 100644
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +module Elasticsearch | ||
2 | + module Entities | ||
3 | + class Result < Api::Entity | ||
4 | + root "results","result" | ||
5 | + | ||
6 | + expose :type do |object, options| | ||
7 | + options[:types].detect { |type| type.to_s.upcase if object.is_a? (type.to_s.classify.constantize) } | ||
8 | + end | ||
9 | + | ||
10 | + expose :name | ||
11 | + | ||
12 | + expose :author, if: lambda { |object,options| object.respond_to? 'author'} do |object, options| | ||
13 | + object.author.present? ? object.author.name : "" | ||
14 | + end | ||
15 | + end | ||
16 | + end | ||
17 | +end |
plugins/elasticsearch/lib/ext/text_article.rb
@@ -4,8 +4,8 @@ require_relative '../elasticsearch_indexed_model' | @@ -4,8 +4,8 @@ require_relative '../elasticsearch_indexed_model' | ||
4 | class TextArticle | 4 | class TextArticle |
5 | def self.control_fields | 5 | def self.control_fields |
6 | { | 6 | { |
7 | - :advertise => nil, | ||
8 | - :published => nil, | 7 | + :advertise => {}, |
8 | + :published => {}, | ||
9 | } | 9 | } |
10 | end | 10 | end |
11 | include ElasticsearchIndexedModel | 11 | include ElasticsearchIndexedModel |
plugins/elasticsearch/lib/ext/uploaded_file.rb
@@ -4,8 +4,8 @@ require_relative '../elasticsearch_indexed_model' | @@ -4,8 +4,8 @@ require_relative '../elasticsearch_indexed_model' | ||
4 | class UploadedFile | 4 | class UploadedFile |
5 | def self.control_fields | 5 | def self.control_fields |
6 | { | 6 | { |
7 | - :advertise => nil, | ||
8 | - :published => nil, | 7 | + :advertise => {}, |
8 | + :published => {}, | ||
9 | } | 9 | } |
10 | end | 10 | end |
11 | include ElasticsearchIndexedModel | 11 | include ElasticsearchIndexedModel |
plugins/elasticsearch/test/test_helper.rb
1 | require 'test_helper' | 1 | require 'test_helper' |
2 | +require_relative '../../../test/api/test_helper.rb' | ||
2 | 3 | ||
3 | -class ElasticsearchTestHelper < ActionController::TestCase | 4 | +module ElasticsearchTestHelper |
4 | 5 | ||
5 | def setup | 6 | def setup |
6 | setup_environment | 7 | setup_environment |
8 | + create_instances | ||
7 | import_instancies | 9 | import_instancies |
8 | end | 10 | end |
9 | 11 | ||
12 | + def create_instances | ||
13 | + end | ||
14 | + | ||
10 | def teardown | 15 | def teardown |
11 | indexed_models.each {|model| | 16 | indexed_models.each {|model| |
12 | model.__elasticsearch__.client.indices.delete index: model.index_name | 17 | model.__elasticsearch__.client.indices.delete index: model.index_name |
@@ -16,9 +21,10 @@ class ElasticsearchTestHelper < ActionController::TestCase | @@ -16,9 +21,10 @@ class ElasticsearchTestHelper < ActionController::TestCase | ||
16 | def import_instancies | 21 | def import_instancies |
17 | indexed_models.each {|model| | 22 | indexed_models.each {|model| |
18 | model.__elasticsearch__.create_index! | 23 | model.__elasticsearch__.create_index! |
24 | + sleep 2 | ||
19 | model.import | 25 | model.import |
26 | + sleep 1 | ||
20 | } | 27 | } |
21 | - sleep 2 | ||
22 | end | 28 | end |
23 | 29 | ||
24 | def setup_environment | 30 | def setup_environment |
@@ -31,7 +37,7 @@ class ElasticsearchTestHelper < ActionController::TestCase | @@ -31,7 +37,7 @@ class ElasticsearchTestHelper < ActionController::TestCase | ||
31 | end | 37 | end |
32 | 38 | ||
33 | def indexed_fields model | 39 | def indexed_fields model |
34 | - model.mappings.to_hash[model.name.downcase.to_sym][:properties] | 40 | + model.mappings.to_hash[model.name.underscore.to_sym][:properties] |
35 | end | 41 | end |
36 | 42 | ||
37 | end | 43 | end |
plugins/elasticsearch/test/unit/api/elasticsearch_plugin_api_test.rb
0 → 100644
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | ||
2 | + | ||
3 | +class ElasticsearchPluginApiTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
6 | + | ||
7 | + def indexed_models | ||
8 | + [Community, Person] | ||
9 | + end | ||
10 | + | ||
11 | + def create_instances | ||
12 | + 7.times.each {|index| create_user "person_#{index}"} | ||
13 | + 4.times.each {|index| fast_create Community, name: "community_#{index}", created_at: Date.new } | ||
14 | + end | ||
15 | + | ||
16 | + should 'show all types avaliable in /search/types endpoint' do | ||
17 | + get "/api/v1/search/types" | ||
18 | + json = JSON.parse(last_response.body) | ||
19 | + assert_equal 200, last_response.status | ||
20 | + assert_equal ElasticsearchHelper::searchable_types.stringify_keys.keys, json["types"] | ||
21 | + end | ||
22 | + | ||
23 | + should 'respond with endpoint /search with more than 10 results' do | ||
24 | + get "/api/v1/search" | ||
25 | + json = JSON.parse(last_response.body) | ||
26 | + assert_equal 200, last_response.status | ||
27 | + assert_equal 10, json["results"].count | ||
28 | + end | ||
29 | + | ||
30 | + should 'respond with query in downcase' do | ||
31 | + get "/api/v1/search?query=person_" | ||
32 | + json = JSON.parse(last_response.body) | ||
33 | + assert_equal 200, last_response.status | ||
34 | + assert_equal 7, json["results"].count | ||
35 | + end | ||
36 | + | ||
37 | + should 'respond with query in upcase' do | ||
38 | + get "/api/v1/search?query=PERSON_" | ||
39 | + json = JSON.parse(last_response.body) | ||
40 | + assert_equal 200, last_response.status | ||
41 | + assert_equal 7, json["results"].count | ||
42 | + end | ||
43 | + | ||
44 | + should 'respond with selected_type' do | ||
45 | + get "/api/v1/search?selected_type=community" | ||
46 | + json = JSON.parse(last_response.body) | ||
47 | + assert_equal 200, last_response.status | ||
48 | + assert_equal 4, json["results"].count | ||
49 | + end | ||
50 | + | ||
51 | +end |
plugins/elasticsearch/test/unit/controllers/elasticsearch_plugin_controller_test.rb
1 | require "#{File.dirname(__FILE__)}/../../test_helper" | 1 | require "#{File.dirname(__FILE__)}/../../test_helper" |
2 | 2 | ||
3 | -class ElasticsearchPluginControllerTest < ElasticsearchTestHelper | 3 | +class ElasticsearchPluginControllerTest < ActionController::TestCase |
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
4 | 6 | ||
5 | def indexed_models | 7 | def indexed_models |
6 | [Community, Person] | 8 | [Community, Person] |
7 | end | 9 | end |
8 | 10 | ||
9 | - def setup | ||
10 | - create_instances | ||
11 | - super | ||
12 | - end | ||
13 | - | ||
14 | - def teardown | ||
15 | - super | ||
16 | - end | ||
17 | - | ||
18 | def create_instances | 11 | def create_instances |
19 | create_people | 12 | create_people |
20 | create_communities | 13 | create_communities |
plugins/elasticsearch/test/unit/elasticsearch_test.rb
1 | require "#{File.dirname(__FILE__)}/../test_helper" | 1 | require "#{File.dirname(__FILE__)}/../test_helper" |
2 | 2 | ||
3 | -class ElasticsearchTest < ElasticsearchTestHelper | 3 | +class ElasticsearchTest < ActionController::TestCase |
4 | 4 | ||
5 | should 'be return yellow for health status' do | 5 | should 'be return yellow for health status' do |
6 | cluster = Elasticsearch::Model.client.cluster | 6 | cluster = Elasticsearch::Model.client.cluster |
plugins/elasticsearch/test/unit/models/community_test.rb
1 | require "#{File.dirname(__FILE__)}/../../test_helper" | 1 | require "#{File.dirname(__FILE__)}/../../test_helper" |
2 | 2 | ||
3 | -class CommunityTest < ElasticsearchTestHelper | 3 | +class CommunityTest < ActionController::TestCase |
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
4 | 6 | ||
5 | def indexed_models | 7 | def indexed_models |
6 | [Community] | 8 | [Community] |
plugins/elasticsearch/test/unit/models/event_test.rb
1 | require "#{File.dirname(__FILE__)}/../../test_helper" | 1 | require "#{File.dirname(__FILE__)}/../../test_helper" |
2 | 2 | ||
3 | -class EventTest < ElasticsearchTestHelper | 3 | +class EventTest < ActionController::TestCase |
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
4 | 6 | ||
5 | def indexed_models | 7 | def indexed_models |
6 | [Event] | 8 | [Event] |
plugins/elasticsearch/test/unit/models/person_test.rb
1 | require "#{File.dirname(__FILE__)}/../../test_helper" | 1 | require "#{File.dirname(__FILE__)}/../../test_helper" |
2 | 2 | ||
3 | -class PersonTest < ElasticsearchTestHelper | 3 | +class PersonTest < ActionController::TestCase |
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
4 | 6 | ||
5 | def indexed_models | 7 | def indexed_models |
6 | [Person] | 8 | [Person] |
plugins/elasticsearch/test/unit/models/text_article_test.rb
0 → 100644
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | ||
2 | + | ||
3 | +class TextArticleTest < ActionController::TestCase | ||
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
6 | + | ||
7 | + def indexed_models | ||
8 | + [TextArticle] | ||
9 | + end | ||
10 | + | ||
11 | + def setup | ||
12 | + super | ||
13 | + end | ||
14 | + | ||
15 | + should 'index searchable fields for TextArticle model' do | ||
16 | + TextArticle::SEARCHABLE_FIELDS.each do |key, value| | ||
17 | + assert_includes indexed_fields(TextArticle), key | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + should 'index control fields for TextArticle model' do | ||
22 | + TextArticle::control_fields.each do |key, value| | ||
23 | + assert_includes indexed_fields(TextArticle), key | ||
24 | + assert_includes indexed_fields(TextArticle)[key][:type], value[:type] || 'string' | ||
25 | + end | ||
26 | + end | ||
27 | + | ||
28 | +end |
plugins/elasticsearch/test/unit/models/uploaded_file_test.rb
0 → 100644
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | ||
2 | + | ||
3 | +class UploadedFileTest < ActionController::TestCase | ||
4 | + | ||
5 | + include ElasticsearchTestHelper | ||
6 | + | ||
7 | + def indexed_models | ||
8 | + [UploadedFile] | ||
9 | + end | ||
10 | + | ||
11 | + def setup | ||
12 | + super | ||
13 | + end | ||
14 | + | ||
15 | + should 'index searchable fields for UploadedFile model' do | ||
16 | + UploadedFile::SEARCHABLE_FIELDS.each do |key, value| | ||
17 | + assert_includes indexed_fields(UploadedFile), key | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + should 'index control fields for UploadedFile model' do | ||
22 | + UploadedFile::control_fields.each do |key, value| | ||
23 | + assert_includes indexed_fields(UploadedFile), key | ||
24 | + assert_includes indexed_fields(UploadedFile)[key][:type], value[:type].presence || 'string' | ||
25 | + end | ||
26 | + end | ||
27 | + | ||
28 | +end |