メニュー
Amazon Simple Notification Service
開発者ガイド (API バージョン 2010-03-31)

Amazon SNS でのメッセージのフィルタリング

デフォルトでは、Amazon SNS トピックの受信者は、トピックに対して発行されたすべてのメッセージを受信します。受信者は、メッセージのサブセットのみを受信するには、トピックのサブスクリプションにフィルタポリシーを割り当てます。

フィルタポリシーはシンプルな JSON オブジェクトです。このポリシーには、受信者が受信するメッセージを定義する属性が含まれています。トピックにメッセージを発行すると、Amazon SNS はトピックの各サブスクリプションのフィルタポリシー内の属性と、メッセージ属性を比較します。属性間に一致がある場合、Amazon SNS は受信者にメッセージを送信します。それ以外の場合、Amazon SNS はメッセージを送信することなく、受信者をスキップします。サブスクリプションにフィルタポリシーがない場合は、そのトピックに発行されたすべてのメッセージが受信されます。

フィルタポリシーでは、メッセージのフィルタ条件をトピックのサブスクリプションに統合して、Amazon SNS の使用を簡略化できます。この統合により、受信者からのメッセージのフィルタリングロジックと、発行者からのメッセージのルーティングロジックをオフロードすることができます。したがって、各フィルタリング条件について個別のトピックを作成してメッセージをフィルタリングする必要はありません。代わりに、単一のトピックを使用でき、属性でメッセージを差別化することができます。各受信者は、そのフィルタポリシーによって許可されたメッセージのみを受信および処理します。

たとえば、オンライン小売サイトのトランザクションによって生成されたすべてのメッセージを発行する単一のトピックを作成できます。各メッセージに対して、トランザクションのタイプを示す属性 (order_placedorder_cancelledorder_declined など) を割り当てることができます。フィルタポリシーでサブスクリプションを作成することで、メッセージのトランザクションタイプを処理するよう意図されたキューに各メッセージをルーティングできます。

AWS マネジメントコンソールを使用してメッセージのフィルタリングを実装する方法を示すチュートリアルについては、「トピックに発行されたメッセージのフィルタリング」を参照してください。このチュートリアルでは、フィルタポリシーを適用してメッセージをルーティングし、Amazon SQS キューを分割する方法を示します。

サブスクリプションフィルタポリシー

フィルタポリシーは Amazon SNS サブスクリプションに割り当てます。ポリシーでは、属性名を指定し、名前ごとに 1 つ以上の値のリストを割り当てます。サブスクリプションでは、サブスクリプションのフィルタポリシーで指定されたものと一致する属性がメッセージに含まれている場合のみ、メッセージを受け取ります。具体的には、次の場合に、サブスクリプションはメッセージを受け取ります。

  1. フィルタポリシーの各属性名が、メッセージに割り当てられた属性名と一致する。

  2. 一致する属性名ごとに、フィルタポリシーとメッセージの名前に割り当てられた値の間に、少なくとも 1 つの一致が存在する。

Amazon SNS がポリシーに対してメッセージ属性を評価する際に、ポリシーに指定されていないメッセージ属性は無視されます。

以下の例では、トピックに発行されたメッセージをフィルタポリシーが受け入れるか拒否するかを示します。

メッセージ例と属性

以下の例は、顧客のトランザクションを公開する Amazon SNS トピックによって送信されるメッセージペイロードを示しています。このメッセージには、トランザクションについて記述する属性 (ストアの名前、イベントのタイプ、顧客の興味の対象、購入金額) が含まれています。

{ "Type" : "Notification", "MessageId" : "e3c4e17a-819b-5d95-a0e8-b306c25afda0", "TopicArn" : "arn:aws:sns:us-east-1:111122223333:MySnsTopic", "Message" : message body with transaction details . . . "Timestamp" : "2017-11-07T23:28:01.631Z", "SignatureVersion" : "1", "Signature" : signature . . . "UnsubscribeURL" : unsubscribe URL . . . "MessageAttributes" : { "customer_interests" : {"Type":"String.Array","Value":"[\"soccer\", \"rugby\", \"hockey\"]"}, "store" : {"Type":"String","Value":"example_corp"}, "event" : {"Type":"String","Value":"order_placed"}, "price_usd" : {"Type":"Number","Value":210.75} } }

メッセージへの属性の適用の詳細については、「Amazon SNS メッセージ属性の使用」を参照してください。

このメッセージには属性が含まれるため、フィルタポリシーを含むすべてのトピックのサブスクリプションでは、メッセージを選択的に許可または拒否することができます。

フィルタポリシーの例

次のフィルタポリシーでは、属性の名前と値に基づいてメッセージの例を許可または拒否します。

例 メッセージを許可するポリシー

次のポリシーの属性は、メッセージ例に割り当てられた属性に一致します。

{ "store": ["example_corp"], "event": [{"anything-but":"order_cancelled"}], "customer_interests": ["rugby", "football", "baseball"], "price_usd": [{"numeric":[">=", 100]}] }

このポリシーの 1 つの属性が、メッセージに割り当てられた属性と一致しなかった場合、メッセージは拒否されます。

例 メッセージを拒否するポリシー

次のポリシーでは、その属性と、メッセージ例に割り当てられた属性の間に、複数の不一致があります。

{ "store": ["example_corp"], "event": ["order_cancelled"], "encrypted": [false], "customer_interests": ["basketball", "baseball"] }

不一致が 1 つ以上あると、ポリシーによってメッセージは拒否されます。

encrypted 属性名がメッセージ属性に存在していないため、割り当てられている値にかかわらず、そのポリシー属性によってメッセージが拒否されます。

フィルタポリシー属性には文字列または数値を含めることができます。文字列と数値により、次のオペレーションを使用してメッセージ属性とフィルタメッセージを一致できます。

文字列値の一致

文字列値はポリシー JSON 内で二重引用符で囲まれます。文字列により、次のオペレーションを使用してメッセージ属性に一致させることができます。

完全一致 (ホワイトリスト)

この一致は、ポリシー属性値が 1 つ以上のメッセージ属性値に一致するときに発生します。たとえば、ポリシー属性は次のようになります。

"customer_interests": ["rugby"]

メッセージ属性に一致:

"customer_interests" : {"Type":"String","Value":"rugby"}
「以外」の一致 (ブラックリスト)

ポリシー属性に anything-but キーワードが含まれている場合、そのポリシー属性値を含まないすべてのメッセージ属性に一致します。たとえば、ポリシー属性は次のようになります。

"customer_interests": [{"anything-but":"rugby"}]

次のようなメッセージ属性と一致します。

"customer_interests" : {"Type":"String","Value":"baseball"}

および:

"customer_interests" : {"Type":"String","Value":"football"}

以下を含まない

"customer_interests" : {"Type":"String","Value":"rugby"}
プレフィックスマッチング

ポリシー属性に prefix キーワードが含まれている場合、その値は、指定された文字で始まる任意のメッセージ属性値に一致します。たとえば、ポリシー属性は次のようになります。

"customer_interests": [{"prefix":"bas"}]

次のようなメッセージ属性と一致します。

"customer_interests" : {"Type":"String","Value":"baseball"}

および:

"customer_interests" : {"Type":"String","Value":"basketball"}

以下を含まない

"customer_interests" : {"Type":"String","Value":"rugby"}

数値の一致

数値はポリシー JSON 内で二重引用符で囲まれません。数値により、次のオペレーションを使用してメッセージ属性値に一致させることができます。

完全一致

ポリシー属性値に numeric キーワードと = 演算子が含まれる場合、同じ名前と等しい数値を持つ任意のメッセージ属性に一致します。たとえば、ポリシー属性は次のようになります。

"price_usd": [{"numeric":["=",301.5]}]

次のようなメッセージ属性と一致します。

"price_usd" : {"Type":"Number","Value":301.5}

および:

"price_usd" : {"Type":"Number","Value":3.015e2}
範囲一致

= 演算子に加えて、数値ポリシー属性には <<=>、および >= を含めることができます。たとえば、ポリシー属性は次のようになります。

"price_usd": [{"numeric":["<", 0]}]

負の数値を持つメッセージ属性に一致し、かつ:

"price_usd": [{"numeric":[">", 0, "<=", 150]}]

最大 150 までの正の数値を持つメッセージ属性に一致します。

AND/OR ロジック

AND/OR ロジックは次のようにフィルタポリシーに適用します。

AND ロジック

AND ロジックを適用するには、複数の属性名 (キー) を使用します。たとえば、次のポリシーは以下のようになります。

{ "customer_interests": ["rugby"], "price_usd": [{"numeric":[">", 100]}] }

customer_interests の値が rugby で、かつ price_usd の値が 100 を超えるメッセージに一致します。

OR ロジック

OR ロジックを適用するには、属性値に複数の値を割り当てます。たとえば、ポリシー属性は次のようになります。

"customer_interests": ["rugby", "football", "baseball"]

customer_interests の値が rugbyまたは football あるいは baseball のメッセージに一致します。

制約

フィルタポリシーを作成するときは、以下の制約を覚えておいてください。

  • Amazon SNS は、データ型が StringString.Array、または Number であるメッセージ属性に対してのみポリシー属性を比較します。データ型が Binary のメッセージ属性は無視されます。

  • ポリシーとメッセージの属性の比較では、文字列の大文字と小文字が区別されます。

  • フィルタポリシーには、JSON オブジェクトとして、引用符、数値、および引用符で囲まないキーワード truefalse、および null で囲まれた文字列が含まれます。

  • フィルタポリシーは、最大 10 個の属性名を持つことができます。

  • 数値ポリシー属性は -109~109 までの値とすることができ、小数点以下 5 桁の精度を持ちます。

  • ポリシーの最大サイズは 256 KB です。

  • Amazon SNS API を使用する場合、ポリシー JSON は有効な UTF-8 文字列として渡す必要があります。

  • デフォルトでは、リージョンあたり、AWS アカウントあたり持つことができるフィルタポリシーは最大 100 個です。この制限を引き上げるには、SNS 制限引き上げのケースを送信します。

  • 値の組み合わせの合計は 100 以下でなければなりません。各配列の値の最大数を乗算して、組み合わせの合計を計算します。たとえば、次のポリシーでは、最初の配列には 3 つの値があり、2 番目には 1 つの値、3 番目には 2 つの値があります。組み合わせの合計は 3 x 1 x 2 = 6 として計算されます。

    { "key_a": ["value_one", "value_two", "value_three"], "key_b": ["value_one"], "key_c": ["value_one", "value_two"] }

サブスクリプションフィルタポリシーの適用

Amazon SNS コンソールを使用して、Amazon SNS サブスクリプションにフィルタポリシーを適用できます。または、プログラムでポリシーを適用するには、Amazon SNSAPI、AWS Command Line Interface (AWS CLI)、または Amazon SNS をサポートする AWSSDK (AWS SDK for Java など) を使用できます。

コンソールを使用したフィルタポリシーの適用

フィルタポリシーを適用するには、Amazon SNS コンソールを使用して以下のステップを完了します。

  1. AWS マネジメントコンソールにサインインした後、Amazon SNS コンソール (https://console.aws.amazon.com/sns/v2/home) を開きます。

  2. ナビゲーションペインで [Subscriptions] を選択します。[サブスクリプション] ページには、選択したリージョンのすべての Amazon SNS サブスクリプションが表示されます。

  3. サブスクリプションがない場合は、[Create subscription] を選択し、[Topic ARN]、[Protocol]、および [Endpoint] の値を指定します。

  4. 1 つ以上のサブスクリプションがある場合は、フィルタポリシーを適用するサブスクリプションを選択します。

  5. [Actions] を選択し、メニューの [Edit subscription filter policy] を選択します。

  6. [Edit subscription filter policy] ウィンドウで、フィルタポリシーの JSON 本文を提供します。

  7. [Set subscription filter policy] を選択します。Amazon SNS により、フィルタポリシーがサブスクリプションに適用されます。

AWS CLI を使用したフィルタポリシーの適用

AWS Command Line Interface (AWS CLI) を使用してフィルタポリシーを適用するには、次の例に示すように set-subscription-attributes コマンドを使用します。

$ aws sns set-subscription-attributes --subscription-arn arn:aws:sns: ... --attribute-name FilterPolicy --attribute-value '{"store":["example_corp"],"event":["order_placed"]}'

--attribute-name オプションで、FilterPolicy を指定します。--attribute-value で、JSON ポリシーを指定します。

ポリシーに有効な JSON を提供するには、属性名と値を二重引用符で囲みます。また、ポリシーの引数全体を引用符で囲む必要があります。引用符のエスケープを避けるため、例に示すように、一重引用符を使用してポリシーを囲み、二重引用符を使用して JSON 名と値を囲みます。

フィルタポリシーが適用されたことを確認するには、get-subscription-attributes コマンドを使用します。ターミナル出力の属性には、次の例に示すように、FilterPolicy キーのフィルタポリシーが表示されます。

$ aws sns get-subscription-attributes --subscription-arn arn:aws:sns: ... { "Attributes": { "Endpoint": "endpoint . . .", "Protocol": "https", "RawMessageDelivery": "false", "EffectiveDeliveryPolicy": "delivery policy . . .", "ConfirmationWasAuthenticated": "true", "FilterPolicy": "{\"store\": [\"example_corp\"], \"event\": [\"order_placed\"]}", "Owner": "111122223333", "SubscriptionArn": "arn:aws:sns: . . .", "TopicArn": "arn:aws:sns: . . ." } }

AWS SDK for Java を使用したフィルタポリシーの適用

AWS SDK for Java を使用してフィルタポリシーを適用するには、AmazonSNS クライアントの setSubscriptionAttributes メソッドを使用します。次の例のように、SetSubscriptionAttributesRequest オブジェクトを引数として指定します。

AmazonSNS snsClient = AmazonSNSClientBuilder.defaultClient(); String filterPolicyString = "{\"store\":[\"example_corp\"],\"event\":[\"order_placed\"]}"; SetSubscriptionAttributesRequest request = new SetSubscriptionAttributesRequest(subscriptionArn, "FilterPolicy", filterPolicyString); snsClient.setSubscriptionAttributes(request);

SetSubscriptionAttributesRequest オブジェクトを初期化するには、次の引数を指定します。

  • subscriptionArn – ポリシーを適用するサブスクリプションの Amazon リソースネーム (ARN)。

  • attributeName"FilterPolicy" である必要があります。

  • attributeValue – 文字列としての JSON フィルタポリシー。文字列ポリシーは二重引用符で囲む必要があるため、\"store\" のように、属性名と値を囲む二重引用符を忘れずにエスケープしてください。

SetSubscriptionAttributesRequest クラスでは、フィルタポリシーを文字列として受け取ります。ポリシーを Java コレクションとして定義する場合は、各属性名を値のリストと関連付けるマップを作成します。サブスクリプションにポリシーを割り当てるには、最初にマップのコンテンツからポリシーの文字列バージョンを作成します。次にその文字列を attributeValue 引数として SetSubscriptionAttributesRequest に渡します。

このプロセスを簡素化するには、次のクラス例をアプリケーションに追加し、必要に応じて変更します。

import com.amazonaws.services.sns.AmazonSNS; import com.amazonaws.services.sns.model.SetSubscriptionAttributesRequest; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; public class SNSMessageFilterPolicy { private enum AttributeType { String, Numeric, Prefix, List, AnythingBut } private class Attribute<T> { protected final T value; protected final AttributeType type; public Attribute(AttributeType type, T value) { this.value = value; this.type = type; } public String toString() { switch(type) { case Prefix: return String.format("{\"prefix\":\"%s\"}", value.toString()); case Numeric: return String.format("{\"numeric\":%s}", value.toString()); case List: ArrayList<T> values = (ArrayList<T>)value; return values .stream() .map(entry -> entry.toString()) .collect(Collectors.joining(",", "[", "]")); case AnythingBut: return String.format("{\"anything-but\":\"%s\"}", value); default: return String.format("\"%s\"", value); } } } private class NumericValue<T extends Number> { private final T lower; private final T upper; private final String lowerOp; private final String upperOp; public NumericValue(String op, T value) { lower = value; lowerOp = op; upper = null; upperOp = null; } public NumericValue(String lowerOp, T lower, String upperOp, T upper) { this.lower = lower; this.lowerOp = lowerOp; this.upper = upper; this.upperOp = upperOp; } public String toString() { StringBuffer s = new StringBuffer("[") .append('\"').append(lowerOp).append("\",").append(lower); if (upper != null) { s.append(",\"").append(upperOp).append("\",").append(upper); } s.append("]"); return s.toString(); } } private final Map<String, Attribute> filterPolicy = new HashMap<>(); public void addAttribute(String attributeName, String attributeValue) { filterPolicy.put(attributeName, new Attribute(AttributeType.String, attributeValue)); } public void addAttribute(String attributeName, ArrayList<String> attributeValues) { ArrayList<Attribute> attributes = new ArrayList<>(); for (String s : attributeValues) { attributes.add(new Attribute(AttributeType.String, s)); } filterPolicy.put(attributeName, new Attribute(AttributeType.List, attributes)); } public void addAttributePrefix(String attributeName, String prefix) { filterPolicy.put(attributeName, new Attribute(AttributeType.Prefix, prefix)); } public void addAttributeAnythingBut(String attributeName, String value) { filterPolicy.put(attributeName, new Attribute(AttributeType.AnythingBut, value)); } public <T extends Number> void addAttribute(String attributeName, String op, T value) { filterPolicy.put(attributeName, new Attribute(AttributeType.Numeric, new NumericValue(op, value))); } public <T extends Number> void addAttributeRange( String attributeName, String lowerOp, T lower, String upperOp, T upper) { filterPolicy.put( attributeName, new Attribute(AttributeType.Numeric, new NumericValue(lowerOp, lower, upperOp, upper))); } public void apply(AmazonSNS snsClient, String subscriptionArn) { SetSubscriptionAttributesRequest request = new SetSubscriptionAttributesRequest(subscriptionArn, "FilterPolicy", formatFilterPolicy()); snsClient.setSubscriptionAttributes(request); } public String formatFilterPolicy() { return filterPolicy.entrySet() .stream() .map(entry -> "\"" + entry.getKey() + "\": [" + entry.getValue() + "]") .collect(Collectors.joining(", ", "{", "}")); } }

このクラスでは、マップとして filterPolicy フィールドを保存します。異なる addAttribute メソッドを使用して、ポリシーに属性を追加します。これらのメソッドは属性名を文字列として受け入れ、さまざまなタイプの値を受け入れることに特化されています。値は、文字列、文字列のリスト、数値、または数値の範囲として渡すことができます。anything-but および prefix 属性を追加できます。サブスクリプションにポリシーを適用する準備ができたら、apply メソッドを使用し、AmazonSNS クライアントおよびサブスクリプション ARN を提供します。このメソッドは、filterPolicy マップのコンテンツからポリシー文字列を作成し、そのポリシーを指定されたサブスクリプションに適用します。

次のコードサンプルでは、SNSMessageFilterPolicy クラスの例を初期化して使用する方法を示します。

// Initialize example filter policy class SNSMessageFilterPolicy fp = new SNSMessageFilterPolicy(); // Add filter policy attribute with single value fp.addAttribute("store", "example_corp"); fp.addAttribute("event", "order_placed"); // Add a prefix attribute filterPolicy.addAttributePrefix("customer_interests", "bas"); // Add an anything-but attribute filterPolicy.addAttributeAnythingBut("customer_interests", "baseball"); // Add filter policy attribute with a list of values ArrayList<String> attributeValues = new ArrayList<>(); attributeValues.add("rugby"); attributeValues.add("soccer"); attributeValues.add("hockey"); fp.addAttribute("customer_interests", attributeValues); // Add numeric attribute filterPolicy.addAttribute("price_usd", "=", 0); // Add numeric attribute with a range filterPolicy.addAttributeRange("price_usd", ">", 0, "<=", 100); // Apply filter policy attributes to SNS subscription fp.apply(snsClient, subscriptionArn);

Amazon SNS API を使用したフィルタポリシーの適用

Amazon SNSAPI を使用してフィルタポリシーを適用するには、SetSubscriptionAttributes アクションへのリクエストを作成します。AttributeName パラメータを FilterPolicy に設定し、AttributeValue パラメータをフィルタポリシーの JSON に設定します。

サブスクリプションのフィルタポリシーの削除

サブスクリプションに送信されるメッセージのフィルタ処理を停止するには、サブスクリプションのフィルタポリシーを空の JSON 本文で上書きすることで削除します。このポリシーを削除したら、サブスクリプションは発行されるすべてのメッセージを受け取るようになります。

コンソールを使用したフィルタポリシーの削除

Amazon SNS コンソールを使用してフィルタポリシーを削除するには、以下の手順を実行します。

  1. AWS マネジメントコンソールにサインインした後、Amazon SNS コンソール (https://console.aws.amazon.com/sns/v2/home) を開きます。

  2. ナビゲーションペインで [Subscriptions] を選択します。[サブスクリプション] ページには、選択したリージョンのすべての Amazon SNS サブスクリプションが表示されます。

  3. フィルタポリシーを削除するサブスクリプションを選択します。

  4. [Actions] を選択し、メニューの [Edit subscription filter policy] を選択します。

  5. [Edit subscription filter policy] (サブスクリプションのフィルタポリシーの編集) ウィンドウで、フィルタポリシーに空の JSON 本文 {} を指定します。

  6. [Set subscription filter policy] を選択します。Amazon SNS により、空のフィルタポリシーがサブスクリプションに適用されます。

AWS CLI を使用したフィルタポリシーの削除

AWS CLI を使用してフィルタポリシーを削除するには、set-subscription-attributes コマンドを使用し、--attribute-value 引数に空の JSON 本文を指定します。

$ aws sns set-subscription-attributes --subscription-arn arn:aws:sns: ... --attribute-name FilterPolicy --attribute-value "{}"

AWS SDK for Java を使用したフィルタポリシーの削除

AWS SDK for Java を使用してフィルタポリシーを削除するには、AmazonSNS クライアントの setSubscriptionAttributes メソッドを使用します。フィルタポリシーとして空の JSON 本文を含む文字列を指定します。

AmazonSNS snsClient = AmazonSNSClientBuilder.defaultClient(); SetSubscriptionAttributesRequest request = new SetSubscriptionAttributesRequest(subscriptionArn, "FilterPolicy", "{}"); snsClient.setSubscriptionAttributes(request);

Amazon SNS API を使用したフィルタポリシーの削除

Amazon SNSAPI を使用してフィルタポリシーを削除するには、SetSubscriptionAttributes アクションへのリクエストを行います。AttributeName パラメータを FilterPolicy に設定し、AttributeValue パラメータに空の JSON 本文を指定します。