MQTTとMessagePub+ :トピックの名前と階層化


MQTTのトピック名は、階層区切りを表す/文字を用いて階層化することが可能です。通知系トピックと要求系トピックはこの階層を用いて名前を付けることで、整理しやすくなります。応答系トピックはブローカによって発行されるため、階層の有無はブローカの実装次第ですが、他の名前と衝突しないユニークな名前が発行されることは保証されています。発行された名前をそのまま使えば問題ないでしょう。

階層とワイルドカード


トピックの階層を示す/はどのような意味があるのでしょうか。まず、人間がぱっと見て理解しやすい区切りという効果があります。この場合、/の代わりに_などを用いても同じ効果が得られるでしょう。しかし/を用いることでトピックのワイルドカード指定が可能となります。ワイルドカードは、SUBSCRIBEおよびUNSUBSCRIBEパケットでトピックを指定する際、複数のトピック群にマッチする特別な表記方法です。ワイルドカードには、シングルレベルとマルチレベルの2種類があります。

シングルレベルワイルドカード

+文字を階層に指定することで、その階層の全てとマッチします。具体例を見てみましょう。

  1. a/b/c
  2. a/x/yyy
  3. k/b/t

という3つのトピックがあるとします。

ここでワイルドカードをa/+/+と指定すると、1と2がマッチします。第1階層がaで、第2階層と第3階層は任意の文字列とマッチします。しかし、階層は必ず3階層必要です。例えば、a/+a/+/a/+/+/+といったワイルドカード指定では、1,2,3いずれともマッチしません。また、階層内で+と文字列を組み合わせることはできません。例えば、a/x/+yyといった指定はできません。ひとつの階層全体を+と指定する必要があります。

マルチレベルワイルドカード

#文字を階層に指定することで、その階層以降全てとマッチします。

  1. a/b/c
  2. a/x/yyy
  3. k/b/t

例えば#を指定すると、1,2,3全てとマッチします。a/#を指定すると1と2にマッチします。#の後(右)には名前を続けることはできません。#は先頭に現れるか、/直後に現れることしかできません。シングルレベルワイルドカードとマルチレベルワイルドカードは組み合わせて用いることができます。例えば、+/b/#と指定すると、1と3がマッチします。

階層化のコツ


階層化は、ファイルシステムのディレクトリ構造の作成に似ています。基本的には、大きな概念から始めて、だんだん細分化していくのが典型的な構成です。しかし、どのような階層化が将来にわたってベストかを見通すことは困難です。そこで、将来、階層化のルールを変更できる仕組みを入れておくことが重要です。具体的には、階層化ルールに名前やバージョンを付け、トピックの最も左、すなわち最上位階層に配置します。そして、その階層化ルールに従った階層が右に続いていきます。

階層化ルール名/階層化ルールに従った階層.../.../...

今回、推奨している、通知系、要求系、応答系の3つのトピック種別に基づく階層ルールを、ここでは、Rv1.0 (Rule version 1の意)としましょう。Rv1.0における第2階層は、通知系の場合、通知を表すNotifyのN、要求系の場合、要求を表すRequestのRとします。なお応答系は、ブローカによって自動生成されるトピックを用いるため、ここには現れません。

  • 通知系トピック Rv1.0/N/.../...
  • 要求系トピック Rv1.0/R/.../...

これで最初の2階層のルールは決まりました。これまでの経験から、今のところこの分類方法がベストであると考えています。しかし、より良い分類方法が将来見つかった場合、第1階層のルール名を変えることで、第2階層の分類(通知系、要求系)を変えることができるようになっています。

後続の階層について考えてみましょう。通知系トピックの例を示します。まず、階層に次のような意味を持たせてみましょう。

Rv1.0/N/ビル/階/部屋/機器/情報

すると具体的なトピックはRv1.0/N/Bldg01/04/Aircon/RoomTempのようになります。もし、その部屋にエアコンが2台あったらどうなるでしょう?

  • Rv1.0/N/Bldg01/04/Meeting1/Aircon1/RoomTemp
  • Rv1.0/N/Bldg01/04/Meeting1/Aircon2/RoomTemp

でしょうか。ここで、エアコン以外の機器、例えば照明機器が追加されたとします。

  • Rv1.0/N/Bldg01/04/Meeting1/Light1/Power

そして、全てのエアコンの情報をサブスクライブするのにワイルドカード指定を試してみます。

Rv1.0/N/Bldg01/04/Meeting1/記述できない/+

残念ながらうまく書けません。もし、Rv1.0/N/Bldg01/04/Meeting1/+/+としていすると、照明の通知系トピックまでサブスクライブされてしまいます。階層の切り方がよくなかったようです。階層の意味付けをRv1.0/N/ビル/階/部屋/機器種別/機器識別子/情報のように変更してみましょう。

3つのトピックは以下のようになります。

  • Rv1.0/N/Bldg01/04/Meeting1/Aircon/1/RoomTemp
  • Rv1.0/N/Bldg01/04/Meeting1/Aircon/2/RoomTemp
  • Rv1.0/N/Bldg01/04/Meeting1/Light/1/Power

ワイルドカードでRv1.0/N/Bldg01/04/Meeting1/Aircon/+/+またはRv1.0/N/Bldg01/04/Meeting1/Aircon/#と記述することで全てのAirconの通知系トピックをサブスクライブできます。

この例で分かるように、ワイルドカードである条件に合致したトピック群を一括でサブスクライブするためには、機器種別のような「特徴」を示す階層が必要となるのです。「部屋」という階層も、もしかしたら「会議室」「トイレ」「キッチン」といった「特徴」を表す階層と、1,2,3という識別子を表す階層に分ける必要があるかもしれません。「特徴」は必ずしもひとつとは限りません。「部屋」を例に考えると「来客用トイレ」は「来客用」という特徴と、「トイレ」という特徴を合わせ持っています。このような場合、どちらの特徴を上位階層に持っていくかなど、唯一の正しい答えはありません。この問題は、特徴を表す形容詞の並び順を一意に定めることが難しいということに起因します。例えば「小さく綺麗な白い花」は、「白くて綺麗な小さな花」とも表現できます。トピック階層を設計する時には、階層をできるだけ将来の拡張も含めて予測し、その個数と並びを決めておく必要があるのです。しかし、未来の完全な予測は不可能です。階層を変える時には、ルールのバージョンを上げると良いかもしれません。Rv1.1/N/新しい階層構造といったイメージです。こうすれば、階層の違いを、第1階層で判別できるため、混乱を防ぐことが可能となります。しかし、階層を変える度にバージョンを上げるのも大変です。MessagePub+ では、よりエレガントにこの問題を解決する解決する方法があります。


MQTTとMessagePub+

MQTTとMessagePub+ 目次に戻る

※この記事に掲載されている内容、および製品仕様、所属情報(会社名・部署名)は公開当時のものです。予告なく変更される場合がありますので、あらかじめご了承ください。

関連サービス