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 に答える