Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search suggestions #143

Merged
merged 5 commits into from
Apr 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions app/controllers/v3/suggest_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class V3::SuggestController < ApplicationController
def index
if query.nil?
render status: 400, json: [].to_json
else
render json: get_suggestions
end
end

def get_suggestions
Search::Suggest.new(query, lang: language).get_suggestions
end

def language
params[:l] || params[:language] || 'en'
end

def query
params[:q] || params[:query]
end
end
10 changes: 10 additions & 0 deletions app/controllers/v3/verses_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
class V3::VersesController < ApplicationController
before_action :fix_resource_content
# GET /verses
def index
verses_index
Expand Down Expand Up @@ -100,4 +101,13 @@ def load_translations
.where(translations: translations)
.eager_load(:translations)
end

def fix_resource_content
# user can get translation using ID or Slug
if render_translations?
translation = params[:translations]

params[:translations] = ResourceContent.where(id: translation).or(ResourceContent.where(slug: translation)).first&.id
end
end
end
4 changes: 2 additions & 2 deletions app/models/concerns/searchable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def verse_path
def as_indexed_json(options={})
hash = self.as_json(
only: [:id, :verse_key, :text_madani, :text_indopak, :text_simple],
methods: :verse_path #chapter_names
methods: [:verse_path, :chapter_names]
)

hash[:words] = words.where.not(text_madani: nil).map do |w|
Expand Down Expand Up @@ -81,7 +81,7 @@ def as_indexed_json(options={})

indexes :verse_path, type: 'keyword' # allow user to search by path e.g 1/2, 2/29 etc

# indexes :chapter_names
indexes :chapter_names
indexes "words", type: 'nested' do
indexes :madani,
type: 'text',
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
end

get 'search', to: 'search#index'
get 'suggest', to: 'suggest#index'
end
end

Expand Down
23 changes: 6 additions & 17 deletions lib/search/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,17 @@ def search
def search_defination
{
_source: source_attributes,
query: search_query,
highlight: highlight
query: search_query #,
# highlight: highlight
}
end

def search_query
#hash = if @query.is_arabic?
# [verse_query(@query.query), words_query(@query.query)]
# else
# ids = Translation.where(resource_type: 'Verse').pluck(:language_id).uniq
# available_languages = Language.find(ids).pluck(:iso_code)
# available_languages.map {|lang| trans_query(lang, @query.query)}
# end
#ids = Translation.where(resource_type: 'Verse').pluck(:language_id).uniq.first(10)
#available_languages = Language.find(ids).pluck(:iso_code)

trans_query = []

unless /[:\/]/.match(@query.query)
available_languages = [ "ml", "en", "bs", "az", "cs", "fr", "hi", "es", "fi", "id", "it", "ko", "dv", "bn", "ku",
"de", "am", "al", "fa", "ha", "mrn", "ms", "pl", "ja", "nl", "tr", "ur", "th", "no", "tg",
"ug", "ru", "pt", "ro", "sq", "sw", "so", "sv", "ta", "uz", "zh", "tt"
]
available_languages = %w[ml en bs az cs fr hi es fi id it ko dv bn ku de am al fa ha mrn ms pl ja nl tr ur th
no tg ug ru pt ro sq sw so sv ta uz zh tt]

trans_query = available_languages.map {|lang| trans_query(lang, @query.query)}
end
Expand Down Expand Up @@ -121,7 +109,8 @@ def nested_highlight(filed)
filed => { type: 'fvh'.freeze }
},
tags_schema: 'styled'.freeze
}
},
size: 500
}
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/search/results.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ def prepare_translation(trans, key)
end

def word_hightlight_class(hit)
return 'hlt1' unless hit['highlight']

highlight = hit['highlight'].values.first.first

if matched = highlight.match(/(hlt\ds*)/)
Expand Down
145 changes: 145 additions & 0 deletions lib/search/suggest.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
module Search
class Suggest
attr_accessor :query, :lang, :size

def initialize(query, lang: 'en', size: 10)
@query = Search::Query.new(query)
@lang = lang
@size = size
end

def get_suggestions
process_results Verse.search(search_defination).page(1).per(10)
end

protected
def search_defination
{
_source: source_attributes,
query: suggest_query,
highlight: highlight
}
end

def suggest_query
trans_query = []

unless /[:\/]/.match(@query.query)
available_languages = %w[ml en bs az cs fr hi es fi id it ko dv bn ku de am al fa ha mrn ms pl ja nl tr ur th
no tg ug ru pt ro sq sw so sv ta uz zh tt]

trans_query = available_languages.map { |lang| trans_query(lang, @query.query) }
end

_verse_query = [verse_query(@query.query)]

{ bool: { should: _verse_query + trans_query } }
end

def verse_query(query)
{
multi_match: {
query: query,
fields: [
'verse_key',
'verse_path',
'text_madani.text',
'text_simple.text',
'text_indopak.text',
'chapter_names'
]
}
}
end

def trans_query(lang, query)
# We boost the results if the query matched a translation of the same language as the user requested
lang_boost = 1
if lang == @language
lang_boost = 2
end

{
nested: {
path: "trans_#{lang}",
query: {
match: {
"trans_#{lang}.text": {
query: query,
boost: lang_boost
}
}
},
inner_hits: nested_highlight("trans_#{lang}.text")
}
}
end

def source_attributes
["verse_key", "id"]
end

def highlight
{
fields: {
"text_madani.text" => {
type: 'fvh'.freeze
}
},
tags_schema: 'styled'.freeze
}
end

def nested_highlight(filed)
{
highlight: {
fields: {
filed => { type: 'plain'.freeze },
},
tags_schema: 'styled'.freeze,
number_of_fragments: 1, # Don't highlight entire translation
fragment_size: 90, # return 90 chars around matched word
pre_tags: ['<b>'],
post_tags: ['</b>']
}
}
end

def process_results(es_response)
processed = []

results = es_response.results.results

results.map do |hit|
matched_values = if hit['highlight'].present?
[hit['highlight']['text_madani.text'].first]
else
trans = hit['inner_hits'].detect do |key, value|
value['hits']['total'] > 0
end

next unless trans
trans.last['hits']['hits'].map do |trans_match|
text = trans_match['highlight'].first.last.last
translation_id = trans_match['_source']['resource_content_id']

[text, translation_id]
end
end

verse_key = "#{hit['_source']['verse_key']}"
href = "/#{verse_key.tr ':', '/'}"

matched_values.each do |match|
processed << {
text: match.is_a?(Array) ? match[0] : match,
href: match.is_a?(Array) ? "#{href}?translations=#{match[1]}" : href,
ayah: verse_key
}
end
end

processed
end
end
end
12 changes: 12 additions & 0 deletions spec/controllers/v3/suggest_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
require 'rails_helper'

RSpec.describe V3::SuggestController, type: :controller do

describe "GET #index" do
it "returns http success" do
get :index
expect(response).to have_http_status(:success)
end
end

end