0

在 Rails 应用程序中,我正在尝试和修补在 postgres 中为现有数据添加 fts。这是我所做的:

class AddNameFtsIndexToCompanies < ActiveRecord::Migration
  def up

    execute(<<-'eosql'.strip)
      DROP INDEX IF EXISTS index_companies_name;
      CREATE INDEX index_companies_name
      ON companies
      USING gin( (to_tsvector('english', "companies"."name")) );
    eosql

    execute(<<-'eosql'.strip)
      ALTER TABLE companies ADD COLUMN name_tsv tsvector;

      CREATE TRIGGER tsv_name_update
      BEFORE INSERT OR UPDATE ON companies FOR EACH ROW
      EXECUTE PROCEDURE tsvector_update_trigger(name_tsv, 'pg_catalog.english', name);

      CREATE INDEX index_companies_fts_name ON companies USING GIN (name_tsv);
    eosql
  end

  def down
    execute(<<-'eosql'.strip)
      DROP INDEX IF EXISTS index_companies_name
    eosql

    execute(<<-'eosql'.strip)
      DROP INDEX IF EXISTS index_fts_name;
      DROP TRIGGER IF EXISTS tsv_name_update ON companies;
      ALTER TABLE companies DROP COLUMN name_tsv
    eosql
  end
end

name_tsv 列的值仍为空。但是为了快速测试,我尝试了这个:

input_data = "foo"
Company.where(["to_tsvector(companies.name) @@ plainto_tsquery(?)", input_data ])

并将其与此进行比较:

input_data = "foo"
Company.where(["companies.name ilike ? ", "%#{input_data}%"])

而前者速度较慢。

问题:
1. 为什么速度较慢?
2. 为现有数据填充 tsvector 列的最佳做法是什么?

虽然我的问题与 Rails 应用程序有关,但通常更多的是关于 postgresql fts,所以仍然欢迎任何特定于 postgres 的解决方案。

4

1 回答 1

0

为什么它更慢?

我敢打赌它在这两种情况下都在进行顺序扫描,并且 tsvector 转换比模式匹配慢。

为现有数据填充 tsvector 列的最佳做法是什么?

您需要创建 PostgreSQL 可用于诸如重叠元素之类的操作的索引。Btree 索引(默认)不给你那个。您需要一个 GIN 或 GIST 索引(在这种情况下,最大的区别在于该选择存在读/写性能权衡)。此外,PostgreSQL 不会知道它可以在您的情况下使用索引,因为您没有在索引列上进行查询。相反,您需要的是功能索引。因此,您需要执行以下操作:

CREATE INDEX company_name_idx_fts ON companies USING GIN (to_tsvector(name, 'English'));

然后,您可以根据查询中的全文搜索扫描该函数的输出。

于 2013-10-28T04:13:52.680 回答