在整数类型上使用.matches()

时间:2014-11-18 23:19:47

标签: ruby-on-rails ruby postgresql activerecord arel

我有一个由Postgres支持的Rails 4应用程序,我的一个表看起来像这样:

ActiveRecord::Schema.define(version: 20141117132948) do
  # These are extensions that must be enabled in order to support this database
  enable_extension "plpgsql"
  ...
  create_table "boards", force: true do |t|
    ...
    t.string "part_name", null: false
    t.string "details", limit: 1024
    t.integer "sku", limit: 8, null: false
    t.integer "ct_id", limit: 8, null: false, default: 0
    ...
  end
  ...
end

我希望能够找到与给定搜索字词匹配的所有记录。例如,如果搜索字词为123,那么我希望能够找到part_namedetailsskuct_id包含{{}的所有电路板1}}。例如,我想要一个sku为'9371239583'的电路板,因为它包含序列'123'。

这是我用来查找匹配记录的代码。

123

我知道SQL语句t = Board.arel_table q = params[:q] # This is the search term, e.g. '123' @boards = @boards.where( t[:part_name].matches("%#{q}%") .or(t[:details].matches("%#{q}%")) .or(t[:sku].matches("%#{q}%")) # This doesn't work because 'sku' is an integer .or(t[:ct_id].matches("%#{q}%")) # same here ) 工作正常,但我找不到将两者结合在一起的方法。

有没有办法在不更改数据库架构的情况下解决此问题?

1 个答案:

答案 0 :(得分:2)

你的一个问题是postgres中的默认索引类型是btree,虽然它在LIKE 'blah%'上相当不错,但在LIKE '%blah' [1}并不是很好]。要解决此问题,您应该使用带有pg_trgm扩展名[2]的gist或gin索引。要安装它,您需要在数据库上运行以下命令一次

create extension pg_trgm;

另一个原因是您一次比较多个列。处理这种情况的一种方法是对表达式[3]进行索引。这个的缺点(以及我一般会给你的解决方案)是它会显着减慢更新。

CREATE INDEX board_concat_idx ON boards USING gin ((part_name || ' ' || details || ' ' || sku || ' ' || ct_id) gin_trgm_ops)

最后,您应该拥有以下高性能索引查询:

SELECT * FROM boards WHERE (part_name || ' ' || details || ' ' || sku || ' ' || ct_id) LIKE '%123%'

注意 - 我已经用空格连接了这些列,但是你应该确保使用一个永远不会出现在列或查询中的字符/序列。这很重要,因为您不希望part_name以1结尾,详细信息以23开头,并获得匹配。

PS。我希望你至少在postgres 9.1。另外,我很好奇为什么你需要这个。

  1. http://www.postgresql.org/docs/9.3/static/indexes-types.html
  2. http://www.depesz.com/2011/02/19/waiting-for-9-1-faster-likeilike/
  3. http://www.postgresql.org/docs/9.3/static/indexes-expressional.html