web-dev-qa-db-ja.com

jsonbは*値*または部分的な値で高速検索できますか?他のタイプ?

任意のデータを挿入する必要があるpersonテーブルがあります。私はPostgres 9.4を使用しているので、jsonbが正しい選択のようです。

データの例:

id: 1, name: "Joe Doe", preferences: { color: "red" , toy: "car"}
id: 2, name: "Jane Doe", preferences: { color: "blue", food: "hamburguer" }

問題は、変数値でクエリする必要があることです。例:

好みに「ハンバーガー」を持っているすべての人、および部分的なクエリも可能でなければならないので、「バーグ」を検索すると、レコード2が表示されます。

Json関数を使用して、キーを知っている限り、値を検索できますよね?または、値をすばやく検索する方法はありますか?

私がやろうとしていることは、tsvector列を作成し、jsonをダンプして全文検索を使用して部分クエリを実行することです。

6
Alex Takitani

私は _MATERIALIZED VIEW_ をネストされていない値と検索ツールとしてのトライグラムインデックスとともに使用することをお勧めします。

hstore

ネストされた値が必要ない場合は、hstoreの方が適している場合があります。関数 svals(hstore) を使用して、hstore値のネストを解除します。

追加モジュールhstoreをデータベースごとに1回インストールする必要があります。

_CREATE EXTENSION hstore;
_

テーブル

_CREATE TABLE person AS
SELECT * FROM (
   VALUES
     (1, 'Joe Doe', hstore  'toy=>car, color=>red')
   , (2, 'Jane Doe', 'food=>hamburguer, color=>blue')
   ) t(person_id, name, preferences);
_

マテリアライズドビュー

_CREATE MATERIALIZED VIEW person_pref AS
SELECT p.person_id, j.preference        -- just pref
FROM   person p, svals(p.preferences) j(preference);
_

これは、セットを返す関数svals()に対する暗黙的な_CROSS JOIN LATERAL_です。

トライグラムインデックス

追加モジュール_pg_trgm_をデータベースごとに1回インストールする必要があります。

_CREATE EXTENSION pg_trgm;
_

次に:

_CREATE INDEX person_pref_j_trgm_idx ON person_pref_j
USING gin (preference gin_trgm_ops);
_

詳細:

クエリ

_SELECT *
FROM   person p
WHERE  EXISTS (
   SELECT 1
   FROM   person_pref pp
   WHERE  pp.person_id = p.person_id
   AND    pp.preference ILIKE '%burg%'
   );
_

これはかなり速いことに注意してください。

jsonb

ネストされた値または numericまたはboolean values がある場合、jsonbの方が効率的です。上記と同じことを jsonb_each_text(jsonb) で実行できます。

_CREATE TABLE person AS
SELECT * FROM (
   VALUES
     (1, 'Joe Doe', jsonb  '{"toy": "car", "color": "red"}')
   , (2, 'Jane Doe', '{"food": "hamburguer", "color": "blue"}')
   ) t(person_id, name, preferences);


CREATE MATERIALIZED VIEW person_pref AS
SELECT p.person_id, j.key, j.preference   -- incl. key or just pref?
FROM  person_j p, jsonb_each_text(p.preferences) j(key, preference);
_

同じインデックス、同じクエリ。あなたmightがMVにキーを追加し、それも検索したい場合:

_CREATE INDEX person_pref_trgm_idx ON person_pref_j
USING GIN (key gin_trgm_ops, preference gin_trgm_ops);
_
4