У меня есть поле, в котором я использую JQuery TokenInput для автозаполнения продукта. Чтобы найти продукты, которые я делаю:
def token
@products = Product.order(:name)
respond_to do |format|
format.html
format.json { render json: @products.where("name ILIKE ?", "%#{params[:q]}%").limit(10).order('name DESC') }
end
end
Если у меня есть продукт с именем Rice
и я выполняю поиск по полю, набирая «r», «ri» и «ric», я хочу, чтобы ближайший результат был тем, который соответствует запросу. Однако вместо этого, если у меня в базе данных более 10 различных типов риса, результаты будут "не по порядку", а Rice
окажется на 6-м или 9-м месте из 10 обнаруженных рисов. Для меня рис должен быть первым, а затем рисовый шар или торт, но вместо этого я получаю что-то вроде:
Brown Rice # First result in Tokeninput
Rice Cake
Yellow Rice
Long Grain Rice
Rice Ball
Chinese Rice
Super Rice
Rice
New Rice
The Super Rice Game
Даже если я наберу именно «Рис», я получу нечто похожее на приведенное выше. Я хочу, чтобы это был первый вариант, если набирается r, ri, ric or rice
, но мои результаты не верят в порядок, они хотят только хаоса. Как это сделать?
4 ответа
Вы можете добавить в свою модель Product
следующий метод:
def self.good_search(criteria)
regexp = /#{criteria}/i; # case-insensitive regexp based on your string
result = order(:name).where("name ILIKE ?", "%#{criteria}%").limit(10)
result.sort{|x, y| (x =~ regexp) <=> (y =~ regexp) }
end
Здесь я использую оператор соответствия (= ~), который возвращает позицию, в которой совпало регулярное выражение. Чем раньше встретится «рис», тем ближе будет строка результирующего массива к вершине. Этот метод может не подходить для больших массивов, но для 10 элементов это нормально.
А вот и ваш контроллер:
def token
respond_to do |format|
format.html
format.json { render json: Product.good_search(params[:q]) }
end
end
Удачи!
Полнотекстовый поиск
Мы сделали что-то вроде этого - вы ищете полный текст поиск
Мы сделали нечто похожее на то, что вы ищете на http://firststopcosmeticshop.co.uk - мы сделали это так:
#config/routes.rb
match 'search(/:search)', :to => 'products#search', :as => :search, via: [:get, :post]
#app/controllers/products_controller.rb
def search
@products = Product.search(params[:search])
respond_to do |format|
format.js { render :partial => "elements/livesearch", :locals => {:search => @products, :query => params[:search]} }
format.html { render :index }
end
end
#app/models/product.rb
def self.search(search)
basic_search(name: search, description: search).take(5) #-> uses textacular gem
end
Он использует текстовый гем для PGSQL, но, надеюсь, дает вам некоторое представление о том, как загрузить, выполнить поиск
Код
Для вас я бы порекомендовал выполнить ваш поиск так:
def token
@products = Product.where(name: "%#{params[:q]}%").order(name: :desc)
respond_to do |format|
format.html
format.json { render json: @products.to_json }
end
end
Хотя это не даст прямого ответа на ваш вопрос, я надеюсь, что это даст вам некоторую информацию об эффективности и т. Д.
Я решил свой поиск с помощью этого запроса, и я думаю, что вы тоже можете его использовать, и результаты поиска будут намного лучше. Учитывая строку query
в качестве входных данных, я использовал следующий sql:
select items.*
from items
where lower(items.name) like 'query%' or items.name like '% query%'
order by case when lower(items.name) like 'query%' then 1 else 2 end,
items.name ASC
Это вернет все элементы, у которых есть хотя бы одна работа, соответствующая заказанному результату с теми, которые начинают совпадение первыми.
В Rails это будет примерно так:
Item.where("lower(items.name) like '#{downcase_query}%' or
lower(items.name) like '% #{downcase_query}%'").
order("case when lower(items.name) like '#{downcase_query}%' then 1 else 2 end,
items.name ASC")
В общем, ключ к сортировке чего-либо в Ruby заключается в использовании .sort или .sort_by.
Например, вот такой пример:
% w {банан, яблоко, груша, рис} .sort_by {| word | word.length} # => ["инжир", "груша", "яблоко", "банан"]
Теперь в вашем примере вам нужно указать, какой критерий вы хотите использовать.
Учитывая, что вы хотите сначала вернуть Rice, а затем Rice Ball, я бы предложил добавить метод сортировки, который предпочтительно сначала возвращает Rice, а затем работает с остальными результатами.
Похожие вопросы
Новые вопросы
ruby-on-rails
Ruby on Rails - это полнофункциональная платформа веб-приложений с открытым исходным кодом, написанная на Ruby. Он следует популярной модели фреймворка MVC и известен своим подходом «соглашение поверх конфигурации» при разработке приложений.