LoginSignup
17
2

More than 1 year has passed since last update.

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/1Elixirで使うとたまに謎のコンパイル関連エラーが出て怖いのでElixir用のex2msパッケージを使うと無難そうです。

もっと気軽にetsを使いたい場合

Mapのような感覚でetsを使うだけであれば、match_specは不要です。etsを簡単なモジュールでラップしてやれば気軽にetsを使えると思います。

ご参考までに

17
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
2