Rails: эффективный поиск по имени и фамилии - PullRequest
3 голосов
/ 27 мая 2011

Я пытаюсь создать «окно поиска», которое соответствует пользователям по имени.

Сложность заключается в том, что у пользователя есть имя и фамилия. В каждом из них могут быть пробелы (например, «Jon / Bon Jovi» или «Neil Patrick / Harris»), и я задаюсь вопросом о наиболее эффективном способе обеспечения поиска при объединении обоих имен и фамилии полей.

Список пользователей довольно большой, поэтому производительность является проблемой. Я мог бы просто добавить определение «полное имя» в пользовательскую модель, но я подозреваю, что это не самый мудрый ход. Мое знание индексов многостолбцовых рельсов слабое, но я подозреваю, что есть способ сделать это с помощью индекса с "" в нем? *

Просто чтобы уточнить, мне не нужно нечеткое сопоставление - только точное совпадение подходит ... Мне просто нужно, чтобы оно выполнялось при объединении двух полей.

Приветствия ...

Ответы [ 2 ]

4 голосов
/ 27 мая 2011

Вы можете создать новое поле в вашей базе данных с именем full_name с регулярным индексом, а затем использовать обратный вызов для заполнения этого поля всякий раз, когда запись сохраняется / обновляется:

before_save :populate_full_name

protected

def populate_full_name
  self.full_name = "#{first_name} #{last_name}"
end
2 голосов
/ 27 мая 2011

Если вы можете изменить базу данных , вы можете и должны использовать решение, предоставленное gjb.

Вот решение, которое не требует от вас изменения базы данных. Просто соберите все возможные пары имя / фамилия, которые вы можете получить из окна поиска. Какой-то код:

# this method returns an array of first/last name pairs given the string
# it returns nil when the string does not look like a proper name
# (i.e. "Foo Bar" or "Foo Bar Baz", but not "Foo" or "Foo "
def name_pairs(string)
  return nil unless string =~ /^\w+(\s+\w+)+$/
  words = string.split(/\s+/)  # split on spaces
  result = []
  # in the line below: note that there is ... and .. in the ranges
  1.upto(words.size-1) {|n| result << [words[0...n], words[n..-1]]}
  result.collect {|f| f.collect {|nm| nm.join(" ")}}
end

Этот метод дает вам массив двухэлементных массивов, которые вы можете использовать для создания запроса or. Вот как выглядит метод:

#> name_pairs("Jon Bon Jovi")
=> [["Jon", "Bon Jovi"], ["Jon", "Bon Jovi"]]
#> name_pairs("John Bongiovi")
=> [["John", "Bongiovi"]]
#> name_pairs("jonbonjovi")
=> nil

Конечно, этот метод не идеален (он не использует заглавные буквы, но вы можете сделать это после разбиения) и, вероятно, не оптимален с точки зрения скорости, но он работает. Вы также можете открыть String и добавить туда метод, чтобы вы могли использовать "Jon Bon Jovi".name_pairs.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...