Skip to content

Commit

Permalink
Search suggestions (#143)
Browse files Browse the repository at this point in the history
* Added suggestion API

* bare minimum suggestions

* enable get transaltion using slug

* increase highlight size

* we don't need to highlight ayah text for search!
  • Loading branch information
naveed-ahmad authored and mmahalwy committed Apr 17, 2017
1 parent 41ea46d commit cb81542
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 19 deletions.
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

0 comments on commit cb81542

Please sign in to comment.