PostgreSQLのカーソルに関する前回の記事では、ommonable xpressions(CTE)について説明しました。今日、PostgreSQLのあまり知られていない機能を使用して、カーソルの新しい代替手段を発見し続けています。
前の記事(上記のリンク)でインポートしたデータを使用します。しばらくお待ちください。
わかった?わかりました。
データは自然界の分類図です。基本的な高校の生物学からの思い出として、そのデータはカール・リンネによって王国、門、クラス、目、家族、属、種に編成されています。もちろん、科学は過去250年間でわずかに進歩したため、分類図は21レベルの深さです。 (当然のことながら)itis.hierarchy
というテーブルに階層ツリーがあります。 。
この記事のトピックは、PostgreSQLでltreeを使用する方法です。具体的には、複雑なレコードセットを非常に効率的にトラバースするためにそれらを使用する方法。その意味で、カーソルの別の代理と見なすことができます。
データは(残念ながら私たちにとっては)ltree形式でキュレートされていないため、記事のために少し変換します。
まず、この記事をフォローするために使用しているデータベースにltreeをインストールする必要があります。もちろん、拡張機能をインストールするにはスーパーユーザーである必要があります。
CREATE EXTENSION IF NOT EXISTS ltree;
次に、この拡張機能を使用して、非常に効率的なルックアップを提供します。データをルックアップテーブルに変換する必要があります。この変換を実行するには、前回の記事で説明したCTE手法を使用します。途中で、ラテン語の名前と英語の名前を分類ツリーに追加します。これは、番号、ラテン語の名前、または英語の名前でアイテムを検索するのに役立ちます。
<?prettify lang-sql linenums =1?>
-- We need a little helper function to strip out illegal label names. CREATE OR REPLACE FUNCTION strip_label(thelabel text) RETURNS TEXT AS $$ -- make sure all the characters in the label are legal SELECT SELECT regexp_replace( regexp_replace( regexp_replace( regexp_replace( -- strip anything not alnum (yes, this could be way more accurate) thelabel, '[^[:alnum:]]', '_','g'), -- consolidate underscores '_+', '_', 'g'), -- strip leading/trailing underscores '^_*', '', 'g'), '_*$', '', 'g'); $$ LANGUAGE sql; CREATE MATERIALIZED VIEW itis.world_view AS WITH RECURSIVE world AS ( -- Start with the basic kingdoms SELECT h1.tsn, h1.parent_tsn, h1.tsn::text numeric_taxonomy, -- There is no guarantee that there will be a textual name COALESCE(l1.completename,h1.tsn::text,'')::text latin_taxonomy, -- and again no guarantee of a common english name COALESCE(v1.vernacular_name, lower(l1.completename),h1.tsn::text,'unk')::text english_taxonomy FROM itis.hierarchy h1 LEFT JOIN itis.longnames l1 ON h1.tsn = l1.tsn LEFT JOIN itis.vernaculars v1 ON (h1.tsn, 'English') = (v1.tsn, v1.language) WHERE h1.parent_tsn = 0 UNION ALL SELECT h1.tsn, h1.parent_tsn, w1.numeric_taxonomy || '.' || h1.tsn, w1.latin_taxonomy || '.' || COALESCE(strip_label(l1.completename), h1.tsn::text,'unk'), w1.english_taxonomy || '.' || strip_label(COALESCE(v1.vernacular_name, lower(l1.completename), h1.tsn::text, 'unk')) FROM itis.hierarchy h1 JOIN world w1 ON h1.parent_tsn = w1.tsn LEFT JOIN itis.longnames l1 ON h1.tsn = l1.tsn LEFT JOIN -- just change this to "itis.vernaculars v1" to allow mulitples and all languages. (Millions of records.) (SELECT tsn, min(vernacular_name) vernacular_name FROM itis.vernaculars WHERE language = 'English' GROUP BY tsn) v1 ON (h1.tsn) = (v1.tsn) ) SELECT w2.tsn, w2.parent_tsn, w2.numeric_taxonomy::ltree, w2.latin_taxonomy::ltree latin_taxonomy, w2.english_taxonomy::ltree english_taxonomy FROM world w2 ORDER BY w2.numeric_taxonomy WITH NO DATA;
ちょっと立ち止まって、このクエリで花の匂いを嗅ぎましょう。手始めに、データを入力せずに作成しました。これにより、多くの役に立たないデータを生成する前に、構文上の問題に対処する機会が得られます。共通テーブル式の反復性を使用して、ここでかなり深い構造をまとめています。また、言語テーブルにデータを追加することで、より多くの言語をカバーするように簡単に拡張できます。マテリアライズドビューには、いくつかの興味深いパフォーマンス特性もあります。 REFRESH MATERIALIZED VIEW
が実行されるたびに、テーブルが切り捨てられて再構築されます。 と呼ばれます。
次に行うことは、世界観を刷新することです。主にそれを時々行うのは健康的だからです。ただし、この場合、実際に行われるのは、マテリアライズドビューにitis
からのデータを入力することです。 スキーマ。
REFRESH MATERIALIZED VIEW itis.world_view;
データから600K以上の行を作成するには、数分かかります。
最初の数行は次のようになります:
┌────────────┬─────────┬───────────────────────────────────────────────────────────────────────────────┐
│ parent_tsn │ tsn │ english_taxonomy │
├────────────┼─────────┼───────────────────────────────────────────────────────────────────────────────┤
│ 768374 │ 1009037 │ animals.bilateria.protostomia.ecdysozoa.arthropods.hexapods.insects.winged_in…│
│ │ │…sects.modern_wing_folding_insects.holometabola.ants.ants.aculeata.apoid_wasps…│
│ │ │….cicadakillers.crabroninae.larrini.gastrosericina.gastrosericus.gastrosericus…│
│ │ │…_xanthophilus │
│ 768374 │ 1009038 │ animals.bilateria.protostomia.ecdysozoa.arthropods.hexapods.insects.winged_in…│
│ │ │…sects.modern_wing_folding_insects.holometabola.ants.ants.aculeata.apoid_wasps…│
│ │ │….cicadakillers.crabroninae.larrini.gastrosericina.gastrosericus.gastrosericus…│
│ │ │…_zoyphion │
│ 768374 │ 1009039 │ animals.bilateria.protostomia.ecdysozoa.arthropods.hexapods.insects.winged_in…│
│ │ │…sects.modern_wing_folding_insects.holometabola.ants.ants.aculeata.apoid_wasps…│
│ │ │….cicadakillers.crabroninae.larrini.gastrosericina.gastrosericus.gastrosericus…│
│ │ │…_zyx │
│ 768216 │ 768387 │ animals.bilateria.protostomia.ecdysozoa.arthropods.hexapods.insects.winged_in…│
│ │ │…sects.modern_wing_folding_insects.holometabola.ants.ants.aculeata.apoid_wasps…│
│ │ │….cicadakillers.crabroninae.larrini.gastrosericina.holotachysphex │
│ 768387 │ 1009040 │ animals.bilateria.protostomia.ecdysozoa.arthropods.hexapods.insects.winged_in…│
│ │ │…sects.modern_wing_folding_insects.holometabola.ants.ants.aculeata.apoid_wasps…│
│ │ │….cicadakillers.crabroninae.larrini.gastrosericina.holotachysphex.holotachysph…│
│ │ │…ex_holognathus │
└────────────┴─────────┴───────────────────────────────────────────────────────────────────────────────┘
分類法では、グラフは次のようになります。
もちろん、実際には21レベルの深さで、合計60万件以上のレコードがあります。
今、私たちは楽しい部分に着きます! ltreeは、階層に対して非常に複雑なクエリを実行する方法を提供します。そのためのヘルプはPostgreSQLのドキュメントにあるので、ここではあまり詳しく説明しません。 (非常に迅速に)理解するために、ltreeの各セグメントはラベルと呼ばれます。したがって、このltree kingdom.phylum.class.order.family.genus.species
7つのラベルがあります。
ltreeに対するクエリでは、限定された形式の正規表現のような特殊な表記法が使用されます。
簡単な例を次に示します。Animalia.*.Homo_sapiens
したがって、世界で人類を見つけるためのクエリは次のようになります。
SELECT tsn, parent_tsn, latin_taxonomy, english_taxonomy
FROM itis.world_view WHERE latin_taxonomy ~ 'Animalia.*.Homo_sapiens';
期待される結果:
┌────────┬────────────┬────────────────────────────────────────────────┬─────────────────────────────────────────────┐
│ tsn │ parent_tsn │ latin_taxonomy │ english_taxonomy │
├────────┼────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────┤
│ 180092 │ 180091 │ Animalia.Bilateria.Deuterostomia.Chordata.Vert…│ animals.bilateria.deuterostomia.chordates.v…│
│ │ │…ebrata.Gnathostomata.Tetrapoda.Mammalia.Theria…│…ertebrates.gnathostomata.tetrapoda.mammals.…│
│ │ │….Eutheria.Primates.Haplorrhini.Simiiformes.Hom…│…theria.eutheria.primates.haplorrhini.simiif…│
│ │ │…inoidea.Hominidae.Homininae.Homo.Homo_sapiens │…ormes.hominoidea.Great_Apes.African_apes.ho…│
│ │ │ │…minoids.Human │
└────────┴────────────┴────────────────────────────────────────────────┴─────────────────────────────────────────────┘
もちろん、PostgreSQLはこれをそのままにしておくことはありません。演算子、インデックス、変換、および例の広範なセットがあります。
このテクニックが解き放つ膨大な数の機能を見てみましょう。
ここで、この手法が、部品番号、車両識別番号、部品表構造、その他の分類システムなど、他の複雑なデータタイプに適用されることを想像してみてください。この構造を直接使用するには非常に複雑な学習曲線があるため、この構造をエンドユーザーに公開する必要はありません。しかし、このような非常に強力で実装の複雑さを隠す構造に基づいて「ルックアップ」画面を構築することは完全に可能です。
シリーズの次の記事では、プラグイン言語の使用について説明します。 PostgreSQLでカーソルの代替を見つけるという文脈では、選択した言語を使用して、ニーズに最も適した方法でデータをモデル化します。またね!