简体   繁体   English

Ruby on Rails-搜索具有多个属性的记录

[英]Ruby on Rails - Search through records with multiple attributes

I have written some code to search via a couple of attributes in all my Recipe records. 我已经编写了一些代码,可以通过所有Recipe记录中的几个属性进行搜索。 The code works, but I would like some input on if it's ok, or how to make it better/faster. 该代码有效,但是我希望在确定的范围内输入一些信息,或者如何使其更好/更快。

I have a Recipe model with various attributes including name:string and ingredients:[array of integers] (postgres database). 我有一个食谱模型,具有各种属性,包括name:stringingredients:[array of integers] (postgres数据库)。 The ingredients are the ID's of a separate model Ingredient . 这些成分是单独的模型Ingredient的ID。 This is a learning experience, I don't want to use any gems. 这是一种学习经历,我不想使用任何宝石。

My form index.html.erb 我的表格index.html.erb

<%= form_tag recipes_path, :method => 'get' do %>
  <p>
    <%= text_field_tag :search, params[:search] %>
    <%= collection_select( :ingredients, :ingredient_ids, Ingredient.all, :id, :name, {:include_blank => false, include_hidden: false}, { :multiple => true  } ) -%>
   <%= submit_tag "Search" %>
  </p>
<% end %>

recipes_controller.rb recipes_controller.rb

 def index
    @recipes = Recipe.search(params[:search], params[:ingredients])
  end

recipe.rb recipe.rb

  def self.search(search, ids)
    array = []
    if search && !search.empty?
      meals = where('name ILIKE ?', "%#{search}%")
      meals.each do |meal|
        array.push(meal)
      end
      if ids && !ids.empty?
        ingredients(array, ids)
      else
        return array
      end
    elsif ids && !ids.empty?
      ingredients(all, ids)
    else
      all
    end
  end

  def self.ingredients(meals, ids)
    newarray = []
    if ids
      meals.each do |me|
        a = me.ingredients
        b = ids[:ingredient_ids].map(&:to_i)
        if (b - a).empty?
          newarray.push(me)
        end
      end
      return newarray
    else
      return meals
    end
  end

This works fine at the moment as I don't have many records, but I don't trust that it'll be very fast if I had hundreds or thousands of records. 由于我没有很多记录,因此目前效果很好,但是我不相信如果我有成百上千的记录会很快。 Any advice on improving things? 有什么改进建议吗?

If you know you're going to be searching on one or more columns frequently, try adding a database-level index for those columns. 如果您知道要经常搜索一个或多个列,请尝试为这些列添加数据库级索引。 Without an index, any search will be O(n) time where n is the number of records. 没有索引,任何搜索将是O(n)时间,其中n是记录数。 However, if you use an index, a search will be O(log(n)) time, because with the data ordered by your search column, you can binary search through it. 但是,如果使用索引,则搜索将是O(log(n))时间,因为使用搜索列排序的数据,您可以对它进行二进制搜索。

Take a look at http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/ for more information at how to check if your query performance can be improved. 请查看http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/ ,以获取有关如何检查查询性能是否可以提高的更多信息。

Two other things to consider performance-wise: 从性能角度考虑另外两件事:

1) For your all condition, you might be returning waaaay more records than you want. 1)在所有情况下,您返回的记录可能都比您想要的多。 You may want to consider using pagination (I know you mentioned no other gems, but there are some great gems for pagination out there). 您可能要考虑使用分页(我知道您没有提到其他宝石,但是那里有一些很棒的分页宝石 )。

2) If you do actually want to return a ton of records at once, consider using ActiveRecord's batching (I usually use #find_each) to ensure you don't load everything into memory at once and end up OOM-ing. 2)如果您确实确实想一次返回大量记录,请考虑使用ActiveRecord的批处理 (我通常使用#find_each)来确保您不会立即将所有内容加载到内存中并最终导致OOM-ing。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM