better user name similarity search
This commit is contained in:
@@ -29,36 +29,53 @@ class Domain::UsersController < ApplicationController
|
||||
def search_by_name
|
||||
authorize Domain::User
|
||||
name = params[:name]&.downcase
|
||||
@users =
|
||||
Domain::User
|
||||
.where("name_for_search ilike ?", "%#{name}%")
|
||||
.includes(:avatar)
|
||||
.select("*")
|
||||
# query =
|
||||
# Domain::UserSearchName
|
||||
# .where("name ilike ?", "%#{name}%")
|
||||
# .joins(:user)
|
||||
# .select("*")
|
||||
# .select(
|
||||
# "levenshtein(name, '#{ReduxApplicationRecord.sanitize_sql_like(name)}') as distance",
|
||||
# )
|
||||
# .select(
|
||||
# "(SELECT COUNT(*) FROM domain_user_post_creations dupc WHERE dupc.user_id = domain_users.id) as num_posts",
|
||||
# )
|
||||
# .group(:user_id)
|
||||
# .order(distance: :asc)
|
||||
# .limit(10)
|
||||
# puts "sql: #{query.to_sql}"
|
||||
#
|
||||
name = ReduxApplicationRecord.sanitize_sql_like(name)
|
||||
|
||||
query =
|
||||
Domain::UserSearchName
|
||||
.select("domain_user_search_names.*, domain_users.*")
|
||||
.select("levenshtein(name, '#{name}') as distance")
|
||||
.select(
|
||||
"(SELECT COUNT(*) FROM domain_user_post_creations WHERE user_id = domain_users.id) as num_posts",
|
||||
"(SELECT COUNT(*) FROM domain_user_post_creations dupc WHERE dupc.user_id = domain_users.id) as num_posts",
|
||||
)
|
||||
.select(<<-SQL)
|
||||
(
|
||||
SELECT
|
||||
MIN(levenshtein(name_unnested.name, '#{ReduxApplicationRecord.sanitize_sql_like(name)}')) as distance
|
||||
FROM
|
||||
unnest(string_to_array(name_for_search, '|')) as name_unnested(name)
|
||||
LIMIT 1
|
||||
) as distance
|
||||
SQL
|
||||
.select(<<-SQL)
|
||||
(
|
||||
SELECT
|
||||
name_unnested.name
|
||||
FROM
|
||||
unnest(string_to_array(name_for_search, '|')) as name_unnested(name)
|
||||
ORDER BY
|
||||
levenshtein(name_unnested.name, '#{ReduxApplicationRecord.sanitize_sql_like(name)}') ASC
|
||||
LIMIT 1
|
||||
) as matched_name
|
||||
SQL
|
||||
.order(distance: :asc)
|
||||
.joins(:user)
|
||||
.where(
|
||||
"(name ilike ?) OR (similarity(dmetaphone(name), dmetaphone(?)) > 0.8)",
|
||||
"%#{name}%",
|
||||
name,
|
||||
)
|
||||
.where(
|
||||
"NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM domain_user_search_names dns2
|
||||
WHERE dns2.user_id = domain_user_search_names.user_id
|
||||
AND levenshtein(dns2.name, ?) < levenshtein(domain_user_search_names.name, ?)
|
||||
)",
|
||||
name,
|
||||
name,
|
||||
)
|
||||
.order("distance ASC")
|
||||
.limit(10)
|
||||
|
||||
puts "query: #{query.to_sql}"
|
||||
|
||||
@user_search_names = query
|
||||
end
|
||||
|
||||
sig(:final) do
|
||||
|
||||
@@ -294,7 +294,7 @@ export default function UserSearchBar({ isServerRendered }: PropTypes) {
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
placeholder="Search FurAffinity Users?!?"
|
||||
placeholder="Search Users"
|
||||
defaultValue={state.userName}
|
||||
onChange={(e) => {
|
||||
setState((s) => ({ ...s, typingSettled: false }));
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
json.users @users do |user|
|
||||
json.users @user_search_names do |user_search_name|
|
||||
user = user_search_name.user
|
||||
json.id user.id
|
||||
json.name user.name_for_view
|
||||
json.show_path domain_user_path(user)
|
||||
json.thumb domain_user_avatar_img_src_path(user.avatar, thumb: "64-avatar")
|
||||
json.domain_icon site_icon_path_for_user(user)
|
||||
json.num_posts user.num_posts if user.has_created_posts?
|
||||
json.matched_name user.matched_name
|
||||
json.distance user.distance
|
||||
json.num_posts user_search_name.num_posts if user.has_created_posts?
|
||||
json.matched_name user_search_name.name
|
||||
json.distance user_search_name.distance
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user