구독에서 메시지 필터링

이 페이지에서는 필터를 사용하여 Pub/Sub 구독을 만드는 방법을 설명합니다.

필터를 사용하여 구독에서 메시지를 수신할 때는 필터와 일치하는 메시지만 수신됩니다. Pub/Sub 서비스는 필터와 일치하지 않는 메시지를 자동으로 확인합니다. 메시지의 데이터가 아닌 속성에 따라 메시지를 필터링할 수 있습니다.

주제에 여러 구독을 연결할 수 있고 각 구독은 서로 다른 필터를 포함할 수 있습니다.

예를 들어 전 세계 여러 지역에서 뉴스를 수신하는 주제가 있으면 특정 리전에서만 게시되는 뉴스를 필터링하도록 구독을 구성할 수 있습니다. 이 구성의 경우 주제 메시지 속성 중 하나가 뉴스 게시 리전을 전달하는지 확인해야 합니다.

필터가 포함된 구독에서 메시지를 받으면 Pub/Sub가 자동으로 확인하는 메시지에 대한 아웃바운드 메시지 요금이 발생하지 않습니다. 이러한 메시지에는 메시지 전송 요금 및 탐색 관련 스토리지 요금이 부과됩니다.

필터로 구독 만들기

Pull 및 Push 구독은 필터를 포함할 수 있습니다. 모든 구독자는 StreamingPull API를 사용하는 구독자를 포함하여 필터를 사용하여 구독에서 메시지를 수신할 수 있습니다.

Google Cloud 콘솔, Google Cloud CLI, 클라이언트 라이브러리 또는 Pub/Sub API를 사용하여 필터로 구독을 만들 수 있습니다.

콘솔

필터로 Pull 구독을 만들려면 다음 단계를 따르세요.

  1. Google Cloud 콘솔에서 구독 페이지로 이동합니다.

    구독 페이지로 이동

  2. 구독 만들기를 클릭합니다.

  3. 구독 ID를 입력합니다.

  4. 드롭다운 메뉴에서 하나의 주제를 선택하거나 만듭니다. 구독은 주제에서 메시지를 수신합니다.

  5. 구독 필터 섹션에서 필터 표현식을 입력합니다.

  6. 만들기를 클릭합니다.

필터로 Push 구독을 만들려면 다음 단계를 따르세요.

  1. Google Cloud 콘솔에서 구독 페이지로 이동합니다.

    구독 페이지로 이동

  2. 구독 만들기를 클릭합니다.

  3. 구독 ID를 입력합니다.

  4. 드롭다운 메뉴에서 하나의 주제를 선택하거나 만듭니다. 구독은 주제에서 메시지를 수신합니다.

  5. 전송 유형 섹션에서 Push를 클릭합니다.

  6. 엔드포인트 URL 필드에서 Push 엔드포인트의 URL을 입력합니다.

  7. 구독 필터 섹션에서 필터 표현식을 입력합니다.

  8. 만들기를 클릭합니다.

gcloud

필터로 Pull 구독을 만들려면 gcloud pubsub subscriptions create 명령어를 --message-filter 플래그와 함께 사용합니다.

gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --topic=TOPIC_ID \
  --message-filter='FILTER'

다음을 바꿉니다.

  • SUBSCRIPTION_ID: 생성할 구독의 ID
  • TOPIC_ID: 구독에 연결할 주제의 ID
  • FILTER: 필터링 구문의 표현식

필터로 Push 구독을 만들려면 gcloud pubsub subscriptions create 명령어를 --push-endpoint--message-filter 플래그와 함께 사용합니다.

gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --topic=TOPIC_ID \
  --push-endpoint=PUSH_ENDPOINT \
  --message-filter='FILTER'

다음을 바꿉니다.

  • SUBSCRIPTION_ID: 생성할 구독의 ID
  • TOPIC_ID: 구독에 연결할 주제의 ID
  • PUSH_ENDPOINT: 푸시 구독자가 실행되는 서버의 URL
  • FILTER: 필터링 구문의 표현식

REST

필터로 구독을 만들려면 projects.subscriptions.create 메서드를 사용합니다.

PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID
Authorization: Bearer $(gcloud auth print-access-token)

다음을 바꿉니다.

  • PROJECT_ID: 구독을 만들려는 프로젝트의 프로젝트 ID
  • SUBSCRIPTION_ID: 생성할 구독의 ID

필터로 Pull 구독을 만들려면 요청 본문에 필터를 지정합니다.

{
  "topic": "projects/PROJECT_ID/topics/TOPIC_ID",
  "filter": "FILTER"
}

다음을 바꿉니다.

  • PROJECT_ID: 주제가 있는 프로젝트의 프로젝트 ID
  • TOPIC_ID: 구독에 연결할 주제의 ID
  • FILTER: 필터링 구문의 표현식

필터로 Push 구독을 만들려면 Push 엔드포인트 및 필터를 요청 본문에 지정합니다.

{
  "topic": "projects/PROJECT_ID/topics/TOPIC_ID",
  "pushConfig": {
    "pushEndpoint": "PUSH_ENDPOINT"
  },
  "filter": "FILTER"
}

다음을 바꿉니다.

  • PROJECT_ID: 주제가 있는 프로젝트의 프로젝트 ID
  • TOPIC_ID: 구독에 연결할 주제의 ID
  • PUSH_ENDPOINT: 푸시 구독자가 실행되는 서버의 URL
  • FILTER: 필터링 구문의 표현식

C++

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 C++ 설정 안내를 따르세요. 자세한 내용은 Pub/Sub C++ API 참고 문서를 확인하세요.

namespace pubsub = ::google::cloud::pubsub;
namespace pubsub_admin = ::google::cloud::pubsub_admin;
[](pubsub_admin::SubscriptionAdminClient client,
   std::string const& project_id, std::string topic_id,
   std::string subscription_id) {
  google::pubsub::v1::Subscription request;
  request.set_name(
      pubsub::Subscription(project_id, std::move(subscription_id))
          .FullName());
  request.set_topic(
      pubsub::Topic(project_id, std::move(topic_id)).FullName());
  request.set_filter(R"""(attributes.is-even = "false")""");
  auto sub = client.CreateSubscription(request);
  if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists) {
    std::cout << "The subscription already exists\n";
    return;
  }
  if (!sub) throw std::move(sub).status();

  std::cout << "The subscription was successfully created: "
            << sub->DebugString() << "\n";
}

C#

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 C# 설정 안내를 따르세요. 자세한 내용은 Pub/Sub C# API 참고 문서를 확인하세요.


using Google.Cloud.PubSub.V1;
using Grpc.Core;

public class CreateSubscriptionWithFilteringSample
{
    public Subscription CreateSubscriptionWithFiltering(string projectId, string topicId, string subscriptionId, string filter)
    {
        SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
        TopicName topicName = TopicName.FromProjectTopic(projectId, topicId);
        SubscriptionName subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);
        Subscription subscription = null;

        var subscriptionRequest = new Subscription
        {
            SubscriptionName = subscriptionName,
            TopicAsTopicName = topicName,
            Filter = filter
        };

        try
        {
            subscription = subscriber.CreateSubscription(subscriptionRequest);
        }
        catch (RpcException e) when (e.Status.StatusCode == StatusCode.AlreadyExists)
        {
            // Already exists.  That's fine.
        }
        return subscription;
    }
}

Go

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 Go 설정 안내를 따르세요. 자세한 내용은 Pub/Sub Go API 참고 문서를 참조하세요.

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/pubsub"
)

func createWithFilter(w io.Writer, projectID, subID, filter string, topic *pubsub.Topic) error {
	// Receive messages with attribute key "author" and value "unknown".
	// projectID := "my-project-id"
	// subID := "my-sub"
	// filter := "attributes.author=\"unknown\""
	// topic of type https://godoc.org/cloud.google.com/go/pubsub#Topic
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	sub, err := client.CreateSubscription(ctx, subID, pubsub.SubscriptionConfig{
		Topic:  topic,
		Filter: filter,
	})
	if err != nil {
		return fmt.Errorf("CreateSubscription: %w", err)
	}
	fmt.Fprintf(w, "Created subscription with filter: %v\n", sub)
	return nil
}

Java

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 자바 설정 안내를 따르세요. 자세한 내용은 Pub/Sub Java API 참고 문서를 참조하세요.

import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.Subscription;
import java.io.IOException;

public class CreateSubscriptionWithFiltering {
  public static void main(String... args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String topicId = "your-topic-id";
    String subscriptionId = "your-subscription-id";
    String filter = "attributes.author=\"unknown\"";

    createSubscriptionWithFilteringExample(projectId, topicId, subscriptionId, filter);
  }

  public static void createSubscriptionWithFilteringExample(
      String projectId, String topicId, String subscriptionId, String filter) throws IOException {
    try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {

      ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
      ProjectSubscriptionName subscriptionName =
          ProjectSubscriptionName.of(projectId, subscriptionId);

      Subscription subscription =
          subscriptionAdminClient.createSubscription(
              Subscription.newBuilder()
                  .setName(subscriptionName.toString())
                  .setTopic(topicName.toString())
                  // Receive messages with attribute key "author" and value "unknown".
                  .setFilter(filter)
                  .build());

      System.out.println(
          "Created a subscription with filtering enabled: " + subscription.getAllFields());
    }
  }
}

Node.js

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 Node.js 설정 안내를 따르세요. 자세한 내용은 Pub/Sub Node.js API 참고 문서를 참조하세요.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';
// const filterString = 'YOUR_FILTER_STRING';   // e.g. 'attributes.author="unknown"'

// Imports the Google Cloud client library
const {PubSub} = require('@google-cloud/pubsub');

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

async function createSubscriptionWithFilter(
  topicNameOrId,
  subscriptionNameOrId,
  filterString
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      filter: filterString,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with filter ${filterString}.`
  );
}

Node.js

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 Node.js 설정 안내를 따르세요. 자세한 내용은 Pub/Sub Node.js API 참고 문서를 참조하세요.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';
// const filterString = 'YOUR_FILTER_STRING';   // e.g. 'attributes.author="unknown"'

// Imports the Google Cloud client library
import {PubSub} from '@google-cloud/pubsub';

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

async function createSubscriptionWithFilter(
  topicNameOrId: string,
  subscriptionNameOrId: string,
  filterString: string
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      filter: filterString,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with filter ${filterString}.`
  );
}

PHP

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 PHP 설정 안내를 따르세요. 자세한 내용은 Pub/Sub PHP API 참고 문서를 참조하세요.

use Google\Cloud\PubSub\PubSubClient;

/**
 * Creates a Pub/Sub subscription.
 *
 * @param string $projectId  The Google project ID.
 * @param string $topicName  The Pub/Sub topic name.
 * @param string $subscriptionName  The Pub/Sub subscription name.
 * @param string $filter  The Pub/Sub subscription filter.
 */
function create_subscription_with_filter(
    string $projectId,
    string $topicName,
    string $subscriptionName,
    string $filter
): void {
    $pubsub = new PubSubClient([
        'projectId' => $projectId,
    ]);
    $topic = $pubsub->topic($topicName);
    $subscription = $topic->subscription($subscriptionName);

    $subscription->create(['filter' => $filter]);

    printf('Subscription created: %s' . PHP_EOL, $subscription->name());
    printf('Subscription info: %s' . PHP_EOL, json_encode($subscription->info()));
}

Python

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 Python 설정 안내를 따르세요. 자세한 내용은 Pub/Sub Python API 참고 문서를 참조하세요.

from google.cloud import pubsub_v1

# TODO(developer): Choose an existing topic.
# project_id = "your-project-id"
# topic_id = "your-topic-id"
# subscription_id = "your-subscription-id"
# filter = "attributes.author=\"unknown\""

publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()
topic_path = publisher.topic_path(project_id, topic_id)
subscription_path = subscriber.subscription_path(project_id, subscription_id)

with subscriber:
    subscription = subscriber.create_subscription(
        request={"name": subscription_path, "topic": topic_path, "filter": filter}
    )
    print(f"Created subscription with filtering enabled: {subscription}")

Ruby

이 샘플을 시도하기 전에 빠른 시작: 클라이언트 라이브러리 사용의 Ruby 설정 안내를 따르세요. 자세한 내용은 Pub/Sub Ruby API 참고 문서를 참조하세요.

require "google/cloud/pubsub"

# Shows how to create a new subscription with filter for a given topic
class PubsubCreateSubscriptionWithFilter
  def create_subscription_with_filter project_id:, topic_id:, subscription_id:, filter:
    pubsub = Google::Cloud::Pubsub.new project_id: project_id
    topic = pubsub.topic topic_id
    subscription = topic.subscribe subscription_id, filter: filter
    puts "Created subscription with filtering enabled: #{subscription_id}"
  end

  def self.run
    # TODO(developer): Replace these variables before running the sample.
    project_id = "your-project-id"
    topic_id = "your-topic-id"
    subscription_id = "id-for-new-subcription"
    filter = "attributes.author=\"unknown\""
    PubsubCreateSubscriptionWithFilter.new.create_subscription_with_filter project_id: project_id,
                                                                           topic_id: topic_id,
                                                                           subscription_id: subscription_id,
                                                                           filter: filter
  end
end

if $PROGRAM_NAME == __FILE__
  PubsubCreateSubscriptionWithFilter.run
end

필터의 최대 길이는 256바이트입니다. 필터는 변경할 수 없는 구독 속성입니다. 구독을 만든 후에는 필터를 수정하기 위해 구독을 업데이트할 수 없습니다.

필터가 백로그 측정항목에 미치는 영향

방금 만든 구독을 모니터링하려면 필터를 사용한 구독 모니터링을 참조하세요.

필터링을 사용 설정한 경우 백로그 측정항목에는 필터와 일치하는 메시지의 데이터만 포함됩니다. 다음은 백로그 측정항목 목록입니다.

  • subscription/backlog_bytes
  • subscription/unacked_bytes_by_region
  • subscription/num_undelivered_messages
  • subscription/num_unacked_messages_by_region
  • subscription/oldest_unacked_message_age
  • subscription/oldest_unacked_message_age_by_region
  • topic/unacked_bytes_by_region
  • topic/num_unacked_messages_by_region
  • topic/oldest_unacked_messages_age_by_region

이러한 측정항목에 대해 자세히 알아보려면 Pub/Sub 측정항목 목록을 참조하세요.

구독 필터 업데이트

기존 구독의 필터는 업데이트할 수 없습니다. 대신 이 해결 방법을 따르세요.

  1. 필터를 변경할 구독의 스냅샷을 만듭니다.

    콘솔을 사용하여 스냅샷을 만드는 방법에 대한 자세한 내용은 스냅샷 만들기를 참조하세요.

  2. 새 필터로 새 구독을 만듭니다.

    필터로 구독을 만드는 방법에 대한 자세한 내용은 필터로 구독 만들기를 참조하세요.

  3. Google Cloud 콘솔에서 Pub/Sub 구독 페이지로 이동합니다.

    구독 페이지로 이동

  4. 방금 만든 구독을 클릭합니다.

  5. 구독 세부정보 페이지에서 메시지 다시보기를 클릭합니다.

  6. 탐색에서 스냅샷까지를 클릭합니다.

  7. 1단계에서 원래 구독에 대해 만든 스냅샷을 선택한 후 탐색을 클릭합니다.

    전환 중에 메시지가 손실되지 않습니다.

  8. 새 구독을 사용하도록 구독자를 변경합니다.

이 절차를 완료한 후에는 원래 구독을 삭제할 수 있습니다.

필터를 만드는 구문

메시지를 필터링하려면 속성으로 작동하는 표현식을 작성합니다. 속성의 키 또는 값과 일치하는 표현식을 작성할 수 있습니다. attributes 식별자는 메시지의 속성을 선택합니다.

예를 들어 다음 테이블의 필터는 name 속성을 선택합니다.

필터 설명
attributes:name name 속성이 있는 메시지
NOT attributes:name name 속성이 없는 메시지
attributes.name = "com" name 속성 및 com 값이 있는 메시지
attributes.name != "com" name 속성 및 com 값이 없는 메시지
hasPrefix(attributes.name, "co") name 속성 및 co로 시작하는 값이 있는 메시지
NOT hasPrefix(attributes.name, "co") name 속성이 없고 co로 시작하는 값이 있는 메시지

필터 표현식의 비교 연산자

다음 비교 연산자를 사용하여 속성을 필터링할 수 있습니다.

  • :
  • =
  • !=

: 연산자는 속성 목록에서 일치하는 키를 찾습니다.

attributes:KEY

등호 연산자는 일치하는 키와 값을 찾습니다. 값은 문자열 리터럴이어야 합니다.

attributes.KEY = "VALUE"

등호 연산자가 있는 표현식은 키로 시작해야 하며 등호 연산자는 키와 값을 비교해야 합니다.

  • 유효: 필터가 키와 값을 비교합니다.

    attributes.name = "com"
    
  • 유효하지 않음: 필터의 왼쪽 측면이 값입니다.

    "com" = attributes.name
    
  • 유효하지 않음: 필터가 두 키를 비교합니다.

    attributes.name = attributes.website
    

키와 값은 대소문자를 구분하며 속성과 정확하게 일치해야 합니다. 키에 하이픈, 밑줄, 영숫자 문자 이외의 문자가 포함된 경우 문자열 리터럴을 사용합니다.

attributes."iana.org/language_tag" = "en"

필터에 백슬래시, 따옴표, 인쇄되지 않는 문자를 사용하려면 문자열 리터럴 내에서 문자를 이스케이프합니다. 문자열 리터럴 내에서 유니코드, 16진수, 8진수 이스케이프 시퀀스를 사용할 수도 있습니다.

  • 유효: 필터가 문자열 리터럴 내의 문자를 이스케이프합니다.

    attributes:"\u307F\u3093\u306A"
    
  • 유효하지 않음: 필터가 문자열 리터럴 없이 문자를 이스케이프합니다.

    attributes:\u307F\u3093\u306A
    

필터 표현식의 불리언 연산자

필터에 부울 연산자 AND, NOT, OR를 사용할 수 있습니다. 연산자는 대문자여야 합니다. 예를 들어 다음 필터는 iana.org/language_tag 속성이 있고 name 속성과 com 값이 없는 메시지에 사용됩니다.

attributes:"iana.org/language_tag" AND NOT attributes.name = "com"

NOT 연산자의 우선순위가 가장 높습니다. ANDOR 연산자를 결합하려면 괄호와 완전한 표현식을 사용합니다.

  • 유효: ANDOR 연산자(괄호 포함)

    attributes:"iana.org/language_tag" AND (attributes.name = "net" OR attributes.name = "org")
    
  • 유효하지 않음: 괄호 없는 ANDOR 연산자

    attributes:"iana.org/language_tag" AND attributes.name = "net" OR attributes.name = "org"
    
  • 유효하지 않음: AND 연산자와 OR 연산자가 불완전한 표현식을 결합함

    attributes.name = "com" AND ("net" OR "org")
    

NOT 연산자 대신 단항 뺄셈 연산자를 사용할 수도 있습니다.

attributes.name = "com" AND -attributes:"iana.org/language_tag"

필터 표현식의 함수

hasPrefix 함수를 사용하여 하위 문자열로 시작하는 값이 있는 속성을 필터링할 수 있습니다. hasPrefix는 필터에서 지원되는 유일한 함수입니다.

hasPrefix 함수에서는 프리픽스 일치가 지원되지만 일반 정규 표현식이 지원되지 않습니다.

hasPrefix(attributes.KEY, "SUBSTRING")

다음을 바꿉니다.

  • KEY: 속성의 이름
  • SUBSTRING: 값의 하위 문자열