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

Improve textSearch_profiles result #3134

Merged
9 changes: 6 additions & 3 deletions app/api/srch/search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ class Search < Grape::API
Search.execute(:all, params)
end

# Request URL should be /api/srch/profiles?srchString=QRY[&seq=KEYCOUNT&showCount=NUM_ROWS&pageNum=PAGE_NUM]
# Request URL should be /api/srch/profiles?srchString=QRY[&sort_by=recent&order_direction=desc&seq=KEYCOUNT&showCount=NUM_ROWS&pageNum=PAGE_NUM]
# Basic implementation from classic plots2 SearchController
desc 'Perform a search of profiles', hidden: false,
is_array: false,
nickname: 'srchGetProfiles'

params do
use :common
use :common, :sorting, :ordering
end
get :profiles do
Search.execute(:profiles, params)
Expand Down Expand Up @@ -105,12 +105,15 @@ def self.execute(endpoint, params)
sresult = DocList.new
search_query = params[:srchString]
tag_query = params[:tagName]
order_query = params[:order_direction]
sort_query = params[:sort_by]
search_type = endpoint
search_criteria = SearchCriteria.new(search_query, tag_query)
search_criteria = SearchCriteria.new(search_query, tag: tag_query, sort_by: sort_query, order_direction: order_query)

if search_criteria.valid?
sresult = ExecuteSearch.new.by(search_type, search_criteria)
end

sparms = SearchRequest.fromRequest(params)
sresult.srchParams = sparms
sresult
Expand Down
8 changes: 8 additions & 0 deletions app/api/srch/shared_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ module SharedParams
optional :tagName, type: String, documentation: { example: 'awesome' }
end

params :ordering do
optional :order_direction, type: String, documentation: { example: 'desc' }
end

params :sorting do
optional :sort_by, type: String, documentation: { example: 'recent' }
end

params :commontypeahead do
requires :srchString, type: String, documentation: { example: 'Spec' }
optional :seq, type: Integer, documentation: { example: 995 }
Expand Down
3 changes: 2 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class User < ActiveRecord::Base
has_many :following_users, through: :active_relationships, source: :followed
has_many :followers, through: :passive_relationships, source: :follower
has_many :likes
has_many :revisions, through: :node

validates_with UniqueUsernameValidator, on: :create
validates_format_of :username, with: /\A[A-Za-z\d_\-]+\z/
Expand All @@ -42,7 +43,7 @@ class User < ActiveRecord::Base
after_destroy :destroy_drupal_user

def self.search(query)
User.where('MATCH(username, bio) AGAINST(?)', query)
User.where('MATCH(bio, username) AGAINST(? IN BOOLEAN MODE)', query + '*')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jywarren gold lesson from this PR about the MySQL fulltext search: the 'IN BOOLEAN MODE' modifier with the * wildcard.

https://dev.mysql.com/doc/refman/8.0/en/fulltext-boolean.html

really glad that this is working now, thanks for the help!

end

def new_contributor
Expand Down
4 changes: 2 additions & 2 deletions app/services/execute_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ def execute(type, search_criteria)
sresult = DocList.new
case type
when :all
sresult = sservice.textSearch_all(search_criteria.query)
sresult = sservice.textSearch_all(search_criteria)
when :profiles
sresult = sservice.textSearch_profiles(search_criteria.query)
sresult = sservice.profiles(search_criteria)
when :notes
sresult = sservice.textSearch_notes(search_criteria.query)
when :questions
Expand Down
22 changes: 20 additions & 2 deletions app/services/search_criteria.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
class SearchCriteria
attr_reader :query, :tag
attr_reader :query, :tag, :sort_by

def initialize(query, tag = nil)
def initialize(query, tag: nil, sort_by: nil, order_direction: "DESC")
@query = query
@tag = tag
@sort_by = sort_by
@order_direction = order_direction
end

def valid?
!query.nil? && query != 0
end

def order_direction
sanitize_direction(@order_direction)
end

private

def sanitize_direction(direction)
if direction.present?
direction = direction.upcase
options = %w(DESC ASC)
options.include?(direction) ? direction : "DESC"
else
"DESC"
end
end
end
44 changes: 30 additions & 14 deletions app/services/search_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,44 +11,60 @@ def initialize; end

# Run a search in any of the associated systems for references that contain the search string
# and package up as a DocResult
def textSearch_all(srchString)
def textSearch_all(search_criteria)
sresult = DocList.new

# notes
noteList = textSearch_notes(srchString)
noteList = textSearch_notes(search_criteria.query)
sresult.addAll(noteList.items)

# Node search
Node.limit(5)
.order('nid DESC')
.where('(type = "page" OR type = "place" OR type = "tool") AND node.status = 1 AND title LIKE ?', '%' + srchString + '%')
.where('(type = "page" OR type = "place" OR type = "tool") AND node.status = 1 AND title LIKE ?', '%' + search_criteria.query + '%')
.select('title,type,nid,path').each do |match|
doc = DocResult.fromSearch(match.nid, match.icon, match.path, match.title, '', 0)
sresult.addDoc(doc)
end
# User profiles
userList = textSearch_profiles(srchString)
userList = profiles(search_criteria)
sresult.addAll(userList.items)

# Tags
tagList = textSearch_tags(srchString)
tagList = textSearch_tags(search_criteria.query)
sresult.addAll(tagList.items)
# maps
mapList = textSearch_maps(srchString)
mapList = textSearch_maps(search_criteria.query)
sresult.addAll(mapList.items)
# questions
qList = textSearch_questions(srchString)
qList = textSearch_questions(search_criteria.query)
sresult.addAll(qList.items)

sresult
end

# Search profiles for matching text and package up as a DocResult
def textSearch_profiles(srchString)
sresult = DocList.new
# Search profiles for matching text with optional order_by=recent param and
# sorted direction DESC by default
# then the list is packaged up as a DocResult

users = SrchScope.find_users(srchString, limit = 10) # don't return hundreds!!
# User profiles
# If no sort_by value present, then it returns a list of profiles ordered by id DESC
# a recent activity may be a node creation or a node revision
def profiles(search_criteria)
user_scope = SrchScope.find_users(search_criteria.query, limit = 10)

user_scope =
if search_criteria.sort_by == "recent"
user_scope.joins(:revisions)
.order("node_revisions.timestamp #{search_criteria.order_direction}")
.distinct

else
user_scope.order(id: :desc)
end

users = user_scope.limit(10)

sresult = DocList.new
users.each do |match|
doc = DocResult.fromSearch(0, 'user', '/profile/' + match.name, match.name, '', 0)
sresult.addDoc(doc)
Expand Down Expand Up @@ -167,10 +183,10 @@ def tagNearbyNodes(srchString, tagName)

# GET X number of latest people/contributors and package up as a DocResult
# X = srchString
def recentPeople(srchString, tagName = nil)
def recentPeople(_srchString, tagName = nil)
sresult = DocList.new

nodes = Node.all.order("changed DESC").limit(srchString).distinct
nodes = Node.all.order("changed DESC").limit(100).distinct
users = []
nodes.each do |node|
if node.author.status != 0
Expand Down
10 changes: 4 additions & 6 deletions app/services/srch_scope.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# This class provides common methods that Typehead and Search services use
class SrchScope
def self.find_users(input, limit)
def self.find_users(query, limit)
if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
User.search(input)
.order('id DESC')
.where(status: 1)
User.search(query)
.where('rusers.status = ?', 1)
.limit(limit)
else
User.order('id DESC')
.where('username LIKE ? AND status = 1', '%' + input + '%')
User.where('username LIKE ? AND rusers.status = 1', '%' + input + '%')
.limit(limit)
end
end
Expand Down
2 changes: 1 addition & 1 deletion db/migrate/20120101000000_drupal_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ def up
unless index_exists? "url_alias", [:dst, :language, :pid], name: "dst_language_pid"
add_index "url_alias", ["dst", "language", "pid"], :name => "dst_language_pid"
end

unless index_exists? "url_alias", [:src, :language, :pid], name: "src_language_pid"
add_index "url_alias", ["src", "language", "pid"], :name => "src_language_pid"
end
Expand Down
13 changes: 13 additions & 0 deletions db/migrate/20180804042601_add_full_text_index_on_username.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class AddFullTextIndexOnUsername < ActiveRecord::Migration[5.2]
def up
if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome!!! 🐎

add_index :rusers, :username, type: :fulltext, name: 'rusers_username_fulltext_idx'
end
end

def down
if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
remove_index :rusers, name: 'rusers_username_fulltext_idx'
end
end
end
Loading