It seems like the main issue is caused by not converting the decoded string to a dictionary before passing it to MySchema. Since you mentioned that the output is in JSON format, you can use the json.loads() function to convert the decoded string to a dictionary.

Here's the modified code with the necessary changes:

import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions
import json
import typing

class MySchema(typing.NamedTuple):
    # your schema definition

TOPIC_PATH = "projects/nectar-259905/topics/events"

def run(pubsub_topic):
    options = PipelineOptions(
        streaming=True
    )
    runner = 'DirectRunner'

    print("I reached before pipeline")

    with beam.Pipeline(runner, options=options) as pipeline:
        message=(
            pipeline
            | "Read from Pub/Sub topic" >> beam.io.ReadFromPubSub(subscription='projects/triple-nectar-259905/subscriptions/bq_subscribe')
            | 'UTF-8 bytes to string' >> beam.Map(lambda msg: msg.decode('utf-8'))
            | 'String to JSON' >> beam.Map(lambda msg: json.loads(msg))
            | 'Map to MySchema' >> beam.Map(lambda msg: MySchema(**msg)).with_output_types(MySchema)
            | "Writing to console" >> beam.Map(print))

        print("I reached after pipeline")
        result = message.run()
        result.wait_until_finish()

run(TOPIC_PATH)

In this code, I've added the 'String to JSON' step to convert the decoded string to a dictionary using json.loads(). This should fix the TypeError you encountered.

Regarding data masking and running SQL within Apache Beam, you can use the beam.Map() and beam.SqlTransform() functions. Here's an example of how to mask the user_id field and run a simple SQL query to filter records with a specific event_id:

def mask_user_id(record: MySchema) -> MySchema:
    masked_user_id = "MASKED-" + record.user_id[-4:]
    return record._replace(user_id=masked_user_id)

with beam.Pipeline(runner, options=options) as pipeline:
    message=(
        pipeline
        # ... previous steps ...
        | 'Map to MySchema' >> beam.Map(lambda msg: MySchema(**msg)).with_output_types(MySchema)
        | 'Mask user_id' >> beam.Map(mask_user_id)
        | 'Filter specific event_id' >> beam.SqlTransform("""
            SELECT * FROM PCOLLECTION
            WHERE event_id = 'Game_Request_Declined'
        """)
        | "Writing to console" >> beam.Map(print))

In this example, I've added a mask_user_id function to mask the user_id field, a Mask user_id step to apply the data masking, and a Filter specific event_id step to filter records using SQL.

Edit
Pub: 26 Mar 2023 10:50 UTC
Views: 137