match_specとは
- etsテーブルのオブジェクトを検索したりするのに使えるErlang独自のクエリ言語
- 表現力では関数に比べて劣るが、Erlangランタイムシステムによってコンパイルされ効率的に動作する
- match_specは自力で書いてもいいのですが、:ets.fun2ms/1関数(もしくはex2msというHexパッケージが提供するEx2ms.fun/1マクロ)が便利です
論よりRUN
基本的なetsテーブルの操作
IExを起動します。
iex
一意のモジュール名で名前をつけてetsのインスタンスを生成。
iex> :ets.new(MyEts, [:set, :named_table])
MyEts
適当にデータを挿入。
iex> :ets.insert(MyEts, [a: 1, b: 2, c: 3, d: 4, e: 5])
true
キーで値を取得。
iex> :ets.lookup(MyEts, :a)
[a: 1]
:ets.lookup/2を使って簡単にキーで検索ができるのですが、それ以上の複雑な検索機能にはmatch_specが必要となります。
全部取得
iex> match_spec = :ets.fun2ms(fn row -> row end)
[{{:"$1", :"$2"}, [], [{{:"$1", :"$2"}}]}]
iex> :ets.select(MyEts, match_spec)
[e: 5, d: 4, c: 3, b: 2, a: 1]
キーを指定
iex> match_spec = :ets.fun2ms(fn {key, _ } = row when key != :b -> row end)
[{{:"$1", :_}, [{:"/=", :"$1", :b}], [:"$_"]}]
iex> :ets.select(MyEts, match_spec)
[e: 5, d: 4, c: 3, a: 1]
値を指定
マッチした列を返す場合
iex> match_spec = :ets.fun2ms(fn { _, value } = row when value in 2..3 -> row end)
[
{{:"$1", :"$2"},
[
{:andalso, {:is_integer, :"$2"},
{:andalso, {:>=, :"$2", 2}, {:"=<", :"$2", 3}}}
], [:"$_"]}
]
iex> :ets.select(MyEts, match_spec)
[c: 3, b: 2]
マッチした列のキーだけを返す場合
iex> match_spec = :ets.fun2ms(fn { key, value } when value in 2..3 -> key end)
[
{{:"$1", :"$2"},
[
{:andalso, {:is_integer, :"$2"},
{:andalso, {:>=, :"$2", 2}, {:"=<", :"$2", 3}}}
], [:"$1"]}
]
iex> :ets.select(MyEts, match_spec)
[:c, :b]
以上、簡単な例を挙げさせていただきました。
ちなみに挿入するデータは別にキーバリューでなくても良いので、空でないタプルであればどんな長さでもOKです。
:ets.insert(MyEts, [{"hello"}, {:x, 1, 2, 3, 4, 5}])
そういった場合にもmatch_specは柔軟に対応できるはずです。タイムスタンプを確認して古いデータを削除など。
mentatというElixirパッケージで古いキャッシュを消去するのにmatch_specが利用されています。
https://github.com/elixir-toniq/mentat/blob/7f1811779ca2dfc80dcb30fe5d70d5809afb3abb/lib/mentat.ex#L228
:ets.fun2ms/1関数とEx2ms.fun/1マクロの違い
これがよくわかりません。個人的にはErlangに備えついている:ets.fun2ms/1関数でいいんじゃないかと思っているのですが、もしEx2ms.fun/1マクロを使う利点についてご存知の方おられましたらお便りください。よろしくお願いいたします。
Erlangの:ets.fun2ms/1はElixirで使うとたまに謎のコンパイル関連エラーが出て怖いのでElixir用のex2msパッケージを使うと無難そうです。
もっと気軽にetsを使いたい場合
Mapのような感覚でetsを使うだけであれば、match_specは不要です。etsを簡単なモジュールでラップしてやれば気軽にetsを使えると思います。
ご参考までに