PostgreSQL 10のICUコレーションを使うと日本語を普通にソートでき、更に文字順序までカスタマイズできる

(Last Updated On: 2017/12/05)

PostgreSQL 10からICU(International Components for Unicode)のロケール/コレーションがサポートされました。

これまでサポートされてきた、libcのja_JPロケールの貧弱な日本語ソート機能とは比べ物にならないくらい高機能な文字比較をサポートしています。日本語や他の言語での照合順序を柔軟に変更できます。

  • マトモな日本語ソート順でソートする(かなり重要)
  • 数字を後にソートする
  • 大文字を先にソートする
  • 仮名を先にソートする
  • 自然ソートする
  • これらをまとめて特別なソート順にする

といったことがPostgreSQL 10から行えます。

基本的な使い方

ja-x-icuはICUサポートが組み込まれている場合、デフォルトで利用可能な日本語ロケールです。ICUロケール(ja-x-icuund-x-icu)はcreatedbコマンドではまだサポートされていないようです。createdbからは使えません。

CREATE DATABASEでも同様です。

 

ICUロケール/コレーションを使うにはCREATE TABLE実行時にCOLLATEを使います。

テーブルをSELECTする際にCOLLATEで指定することも可能です。

 

ICUロケール/コレーションのソート順を確かめる

全角、半角を混ぜた英数と仮名のテストデータを作成します。

ソートなしでSELECTしてみます。

ORDER BYを付けてSELECTします。ja-x-icu コレーションだと概ね一般に期待されるような順序でソートされています。

libcのja_JP(古いPostgreSQLで利用可能なロケール。このブログを書くために使っているOSはFedora 26です。libcロケールのソート順はOSによって異る)の場合は次のように、人間が期待する順番通りにはソートされません。

デフォルトで利用できる”ja-x-icu“(und-x-icu : 言語未定義のロケールもja-x-icuと同様にソートする)だけでも日本語ユーザーにとって画期的なソート結果ですが、ICUロケールの場合は更に色々な設定が可能です。

ICUのロケール/コレーション拡張を利用する

ICUはBCP 47というルールに従ってロケールを定義できます。拡張ルールは”u“を利用して定義します。例えば、PostgreSQLのマニュアルページでも紹介されている

de-u-co-phonebk ロケール/コレーションはICUで定義されている、ドイツ語の電話帳順ソートです。de-u-co-phonebkを使うにはPostgreSQLでロケール/コレーションとして使えるように定義する必要があります。

PostgreSQL 10からICUプロバイダー(provider)が使えます。libcを使う場合はicuの代わりにlibcを指定できます。

CREATE COLLATION de-u-co-phonebk-x-icu (provider = icu, locale = ‘de-u-co-phonebk‘);

実際にこのコレーションを使ってみます。ソート順序が異ることが判ります。

 

数字が英字の前なんて許せない!

数字が優先されることが許せない、と感じていた方には朗報です。簡単に順番を変えれます。拡張ロケール/コレーションはCRATE COLLATIONでコレーションと作ってからでないと使えないことを思い出してください。作れば使えるようになります。

CREATE COLLATION digitslast (provider = icu, locale = ‘ja-u-kr-latn-digit‘);

数字が後にソートされています。

小文字の後に大文字なんて許せない!

個人的には小文字の後に大文字アルファベットがソートされていると違和感が大きいです。これも直せます。

CREATE COLLATION upperfirst (provider = icu, locale = ‘ja-u-kf-upper‘);

 

仮名が英数の後なんて許せない!

これも順番を変更できます。

CREATE COLLATION kanafirst (provider = icu, locale = ‘ja-u-kr-hrkt-latn-digit‘);

 

前の3つを組み合わせる!

仮名を優先ソート、大文字を優先ソート、数字を英字の後にする、をまとめる事も可能です。

CREATE COLLATION special (provider = icu, locale = ‘ja-u-kr-hrkt-latn-digit-kf-upper‘);

 

いわゆる自然ソートでソートしたい!

CREATE COLLATION numeric (provider = icu, locale = ‘ja-u-kn-true‘);

サンプルデータが自然ソート(Natural Sort)向きではないのでソート実行例は省略しますが、自然ソートできます。

ソート例:最近のファイルビューワーのように人が期待する数値順序になる

 

絵文字のソート順がバラバラなのが許せない!

“u-co-emoji”を使えば、絵文字がグループ毎にソートされます。(Uniocde絵文字をサポートしない環境では絵文字は表示されません)

CREATE COLLATION emoji (provider = icu, locale = ‘ja-u-co-emoji‘);

バイナリでソートすると以下のようにバラバラです。

 

 

まとめ

このソート順の為だけにPostgreSQL 10にアップグレードしたくなった!という方も少なくないのでは?!

Unicode Technical Standard #35 と BCP 47 を参照すると機能の詳細が解ります。

CLDR repository と ICU Locale Explorer を参照すると記号のようなロケール文字の意味や定義が解ります。

ソート順序はICUのバージョンによって変わる場合があります。このため、ICUバージョンが異るとエラーが発生することがあります。

 

この場合、適切なバージョンのICUとリンクしたPostgreSQLを使うか、エラーメッセージに記載された通りRERESH VERSIONすると直ります。

ICUロケール文字列にタイポなどがあってもほとんどの場合エラーになりません。思った通りのソートでない場合は先ずタイポを疑いましょう。タイポには注意しましょう。

コレーション(照合順序)を利用するとソート順を定義したテーブルを参照しながらソートします。バイナリソートと比べると遅くなります。どの程度遅くなるかはデータとソート方法(コレーション)によります。既存のデータベースで利用する場合、ベンチマークすることをお勧めします。

 

Comments

comments