optimized people search

This commit is contained in:
danielgrippi 2011-07-28 23:08:37 -07:00 committed by Ilyaaaaaaaaaaaaa Zhitomirskiy
parent 5e39368414
commit f560321626
6 changed files with 53 additions and 26 deletions

View file

@ -47,39 +47,25 @@ class Person < ActiveRecord::Base
def self.search_query_string(query)
if postgres?
where_clause = <<-SQL
profiles.first_name ILIKE ? OR
profiles.last_name ILIKE ? OR
people.diaspora_handle ILIKE ?
profiles.full_name ILIKE ? OR
profiles.diaspora_handle ILIKE ?
SQL
else
where_clause = <<-SQL
profiles.first_name LIKE ? OR
profiles.last_name LIKE ? OR
people.diaspora_handle LIKE ? OR
profiles.first_name LIKE ? OR
profiles.last_name LIKE ?
profiles.full_name LIKE ? OR
people.diaspora_handle LIKE ?
SQL
end
sql = ""
tokens = []
query_tokens = query.to_s.strip.split(" ")
query_tokens.each_with_index do |raw_token, i|
token = "#{raw_token}%"
up_token = "#{raw_token.titleize}%"
sql << " OR " unless i == 0
sql << where_clause
tokens.concat([token, token, token])
tokens.concat([up_token, up_token]) unless postgres?
end
[sql, tokens]
q_tokens = query.to_s.strip.gsub(/(\s|$|^)/) { "%#{$1}" }
[where_clause, [q_tokens, q_tokens]]
end
def self.search(query, user)
return [] if query.to_s.blank? || query.to_s.length < 3
sql, tokens = self.search_query_string(query)
Person.searchable.where(sql, *tokens).joins(
"LEFT OUTER JOIN contacts ON contacts.user_id = #{user.id} AND contacts.person_id = people.id"
).includes(:profile

View file

@ -45,6 +45,7 @@ class Profile < ActiveRecord::Base
end
before_save do
self.build_tags
self.construct_full_name
end
def subscribers(user)
@ -120,6 +121,13 @@ class Profile < ActiveRecord::Base
end
end
# Constructs a full name by joining #first_name and #last_name
# @returns [String] A full name
def construct_full_name
self.full_name = [self.first_name, self.last_name].join(' ').downcase
self.full_name
end
protected
def strip_names
self.first_name.strip! if self.first_name

View file

@ -0,0 +1,22 @@
class AddFullNameToProfile < ActiveRecord::Migration
def self.up
add_column :profiles, :full_name, :string, :limit => 70
add_index :profiles, :full_name
add_index :profiles, [:full_name, :searchable]
remove_index :profiles, [:first_name, :last_name, :searchable]
remove_index :profiles, [:first_name, :searchable]
remove_index :profiles, [:last_name, :searchable]
execute("UPDATE profiles SET full_name=LOWER(CONCAT(first_name, ' ', last_name))")
end
def self.down
remove_index :profiles, :column => :full_name
remove_column :profiles, :full_name
add_index :profiles, [:first_name, :searchable]
add_index :profiles, [:last_name, :searchable]
add_index :profiles, [:first_name, :last_name, :searchable]
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20110710102747) do
ActiveRecord::Schema.define(:version => 20110729045734) do
create_table "aspect_memberships", :force => true do |t|
t.integer "aspect_id", :null => false
@ -295,11 +295,11 @@ ActiveRecord::Schema.define(:version => 20110710102747) do
t.datetime "created_at"
t.datetime "updated_at"
t.string "location"
t.string "full_name", :limit => 70
end
add_index "profiles", ["first_name", "last_name", "searchable"], :name => "index_profiles_on_first_name_and_last_name_and_searchable"
add_index "profiles", ["first_name", "searchable"], :name => "index_profiles_on_first_name_and_searchable"
add_index "profiles", ["last_name", "searchable"], :name => "index_profiles_on_last_name_and_searchable"
add_index "profiles", ["full_name", "searchable"], :name => "index_profiles_on_full_name_and_searchable"
add_index "profiles", ["full_name"], :name => "index_profiles_on_full_name"
add_index "profiles", ["person_id"], :name => "index_profiles_on_person_id"
create_table "service_users", :force => true do |t|

View file

@ -36,7 +36,6 @@ describe Person do
end
end
describe '#diaspora_handle' do
context 'local people' do
it 'uses the pod config url to set the diaspora_handle' do

View file

@ -29,6 +29,18 @@ describe Profile do
end
end
describe '#contruct_full_name' do
it 'generates a full name given first and last names' do
profile = Factory(:person).profile
profile.first_name = "casimiro"
profile.last_name = "grippi"
profile.full_name.should_not == "casimiro grippi"
profile.save
profile.full_name.should == "casimiro grippi"
end
end
describe "of last_name" do
it "strips leading and trailing whitespace" do
profile = Factory.build(:profile, :last_name => " Ohba ")