個人を特定できる情報(PII)を検出および編集する

個人を特定できる情報(PII)には、名前、住所、電話番号、メールアドレス、納税者番号、および個人を特定するために(単独または他の情報と合わせて)使用できるその他のデータが含まれます。ほとんどの組織には、PIIデータの取り扱いに関する規制とコンプライアンス要件があります。:doc:`AI_REDACT</sql-reference/functions/ai_redact>`は、大規模言語モデル(LLM)を使用して非構造化テキストデータからPIIを検出、特定、および編集するのに役立つ、完全に管理されたCortex AI関数です。

AI_REDACTは、コールセンターのコーチング、感情分析、保険および医療分析、機械学習(ML)モデルのトレーニングなど、さまざまなユースケースのためにテキストを準備するのに役立ちます。

Tip

AI_PARSE_DOCUMENT または AI_TRANSCRIBE を使用して、 AI_REDACT を適用する前に、ドキュメントまたはスピーチデータをテキストに変換します。

AI_REDACT

AI_REDACT関数には、detect``と``redact``という2つの操作モードがあります。デフォルトは ``redact です。``detect``モードでAI_REDACTを使用して、PIIの場所を特定し、編集するPIIをプログラムで選択します。``redact``モードでAI_REDACTを使用して、入力テキスト内のPIIをプレースホルダー値に置き換えます。

重要

AI_REDACTは、AIモデルを使用してベストエフォート方式で検出と編集を実行します。出力を常に確認して、組織のデータプライバシーポリシーに準拠していることを確認してください。AI_REDACTがデータ内のPIIの検出または編集に失敗した場合は、:doc:`Snowflakeサポートにお問い合わせ</user-guide/contacting-support>`ください。

リージョンの可用性

リージョンの可用性 をご参照ください。

制限事項

  • 編集は AI モデルを使用して実行され、個人を特定できる情報をすべて検出しない場合があります。出力を常に確認して、組織のデータプライバシーポリシーに準拠していることを確認してください。AI_REDACT が特定の PII の編集に失敗する場合は、Snowflakeサポートにお問い合わせください。

  • COUNT_TOKENS および AI_COUNT_TOKENS 関数はまだ AI_REDACT をサポートしていません。

  • 現時点では、 AI_REDACT は、文法的に正しい英語テキストで最善の機能を発揮します。パフォーマンスは、多くのスペルミス、句読点の誤り、または文法エラーのある他の言語またはテキストでは異なる場合があります。

  • AI_REDACTは現在、:ref:`label-ai_redact_pii_categories`に示されているように、USのPIIとUKおよびカナダの一部のPIIのみをサポートしています。

  • AI_REDACT は現在、入力および出力できるトークンの数が制限されています。入力と出力を合計して、最大4,096トークンを使用できます。出力は1,024トークンに制限されています。入力テキストが長い場合は、 SPLIT_TEXT_RECURSIVE_CHARACTER を使用して、小さなチャンクに分割し、各チャンクを個別に編集します。トークン制限を超えるテキストを編集する例については、:ref:`label-ai_redact_pii_example_chunking`を参照してください。

    注釈

    トークンは、 AI モデルによって処理される最小のデータ単位です。英語のテキストの場合、業界のガイドラインでは、1トークンは約4文字、または0.75単語と見なされます。

検出される PII カテゴリ

AI_REDACTは、以下のカテゴリのPIIの検出と編集をサポートしています。カテゴリ列の値は、オプションの``categories``引数でサポートされている文字列です。

カテゴリ

メモ

NAME

フルネーム、名、ミドルネーム、および姓を認識します

EMAIL

PHONE_NUMBER

DATE_OF_BIRTH

GENDER

男性、女性、ノンバイナリーを認識します

AGE

ADDRESS

識別:

  • 完全な郵便番号(US、 UK、 CA)

  • 住所(US、 UK、 CA)

  • 郵便番号(US、 UK、 CA)

  • 都市(US、 UK、 CA)

  • 州(US)または県(CA)

  • 郡、区、または町(US)

NATIONAL_ID

社会保障番号を識別します(US)

PASSPORT

パスポート番号を識別します(US 、 UK 、 CA)

TAX_IDENTIFIER

個人の納税番号( ITNs )を識別します

PAYMENT_CARD_DATA

完全なカード情報、カード番号、有効期限日、および CVV を識別します

DRIVERS_LICENSE

サポート対象(US、 UK、 CA)

IP_ADDRESS

注釈

AI_REDACT は一部の PII カテゴリの部分的な一致をサポートしています。たとえば、[NAME] プレースホルダーを使用して編集をトリガーするには、名前だけで十分です。

検出モードで特定のPIIを保持する

デフォルトでは、AI_REDACTは検出されたすべてのPIIをプレースホルダー値に置き換えます。場合によっては、特定のPIIを保持しつつ、それ以外については編集したいことがあります。たとえば、コールセンターのトランスクリプトや顧客レビューにおいて、既知の従業員名以外のすべての名前を編集したいことがあります。

選択的な編集ワークフローを構築するには、``detect``モードを使用します。

  1. ``mode``引数を``detect``に設定してAI_REDACTを呼び出し、入力テキスト内のPIIを特定して見つけます。

  2. 検出されたスパンを、保持したい値の許可リストと比較します。

  3. 許可リストにないPIIのみを編集します。

``detect``モードでAI_REDACTを呼び出すと、関数は``spans``配列を含むOBJECTを返します。配列の各要素は、次のフィールドをもつOBJECTです。

フィールド

説明

category

VARCHAR

``NAME``や``ADDRESS``などのPIIカテゴリ。サポートされているカテゴリについては、:ref:`label-ai_redact_pii_categories`を参照してください。

start

NUMBER

入力テキストで検出されたPIIの開始インデックス。

end

NUMBER

入力テキストで検出されたPIIの終了インデックス。

text

VARCHAR

入力から一致したPIIテキスト。

``detect``モードの使用例については、:ref:`label-ai_detect_pii_examples`を参照してください。

複数行のクエリにおける行レベルのエラーを処理する

重要

クエリがすべての行で失敗する場合、原因は行レベルのエラーではなく、既知の制約である可能性があります。トークンの制限、言語のサポート、その他の制限について詳しくは、:ref:`label-ai_redact_pii_limitations`を参照してください。

AI_REDACTが入力テキストを処理できない場合、エラーが発生します。クエリが複数の行を編集する場合、エラーによりクエリ全体が失敗します。処理が他の行で続行するようにするには、セッションパラメーター``AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR``をFALSEに設定します。エラーが発生すると、クエリが停止される代わりに、NULLが返されます。

ALTER SESSION SET AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR=FALSE;
Copy

このパラメーターを FALSE に設定すると、 AI_REDACT の最終引数として TRUEを渡すこともできます。これにより、戻り値は編集されたテキストとエラーメッセージの個別のフィールドを含む OBJECT になります。AI_REDACT 呼び出しが正常に処理されたかどうかに応じて、これらのフィールドの1つが NULL になります。

次の例は、複数の行を処理する際にどのようにエラー処理を使用するかを示しています。

  1. 編集されていないテキストを含むテーブルを作成します。

    CREATE OR REPLACE TABLE raw_table AS
      SELECT 'My previous manager, Washington, used to live in Kirkland. His first name was Mike.' AS my_column
      UNION ALL
      SELECT 'My name is William and I live in San Francisco. You can reach me at (415).450.0973';
    
    Copy
  2. セッションパラメーターを設定します。

    ALTER SESSION SET AI_SQL_ERROR_HANDLING_USE_FAIL_ON_ERROR=FALSE;
    
    Copy
  3. ``value``と``error``の列をもつ編集テーブルを作成します。

    CREATE OR REPLACE TABLE redaction_table (
      value VARCHAR,
      error VARCHAR
      );
    
    Copy
  4. ``raw_table``からPIIを編集し、行を``redaction_table``に挿入して、編集されたテキストとエラーメッセージを格納します。

    INSERT INTO redaction_table
    SELECT
        result:value::STRING AS value,
        result:error::STRING AS error
      FROM (SELECT AI_REDACT(my_column, TRUE) AS result FROM raw_table);
    
    Copy

コストの考慮事項

AI_REDACT は他のCortex AI 関数と同様に、処理される入力と出力トークンの数に基づいてコストが発生します。詳細については、 Snowflakeの価格ガイド をご参照ください。

編集の例

基本的な編集の例

次の例では、入力テキストから名前と住所を編集しています。

SELECT AI_REDACT(
  input => 'My name is John Smith and I live at twenty third street, San Francisco.'
  );
Copy

基本的な編集の出力:

My name is [NAME] and I live at [ADDRESS]

次の例では、入力テキストから名前とメールアドレスのみを編集しています。テキストには名のみが含まれていることに注意してください。これは[NAME]として認識および編集されます。入力テキストにはメールアドレスが含まれていないため、出力にはメールのプレースホルダーは表示されません。

SELECT AI_REDACT(
  input => 'My name is John and I live at twenty third street, San Francisco.',
  categories => ['NAME', 'EMAIL']
  );
Copy

選択的な編集の出力:

My name is [NAME] and I live at twenty third street, San Francisco.

エンド・ツー・エンドの例

次の例では、あるテーブルの行を処理し、編集した出力を別のテーブルに挿入しています。同様の方法を使用して、編集されたデータを既存のテーブルの列に格納できます。編集後、テキストは全体的な感情情報を抽出するために:doc:`AI_SENTIMENT</sql-reference/functions/ai_sentiment>`関数に渡されます。

  1. 編集されていないテキストを含むテーブルを作成します。

    CREATE OR REPLACE TABLE raw_table AS
      SELECT 'My previous manager, Washington, used to live in Kirkland. His first name was Mike.' AS my_column
      UNION ALL
      SELECT 'My name is William and I live in San Francisco. You can reach me at (415).450.0973';
    
    Copy
  2. 編集されていないデータを表示します。

    SELECT * FROM raw_table;
    
    Copy
  3. 編集テーブルを作成します。

    CREATE OR REPLACE TABLE redaction_table (value VARCHAR);
    
    Copy
  4. ``raw_table``からPIIを編集し、行を``redaction_table``に挿入します。

    INSERT INTO redaction_table
      SELECT AI_REDACT(my_column) AS value FROM raw_table;
    
    Copy
  5. 編集された結果を表示します。

    SELECT * FROM redaction_table;
    
    Copy
  6. 編集されたテキストに対してAI_SENTIMENT関数を実行します。

    SELECT
        value AS redacted_text,
        AI_SENTIMENT(value) AS summary_sentiment
      FROM redaction_table;
    
    Copy

チャンキングの例

この例では、テキストを小さなチャンクに分割し、各チャンクを個別に編集し、編集されたチャンクを再結合して最終出力を作成することによって、長いテキストから PII を編集する方法を示します。このアプローチは AI_REDACT のトークン制限で機能します。

  1. 患者データを含むテーブルを作成します。

    CREATE OR REPLACE TABLE patients (
      patient_id INT PRIMARY KEY,
      patient_notes TEXT
      );
    
    Copy
  2. テキストをチャンクに分割し、各チャンクにAI_REDACTを適用して、編集されたチャンクを連結します。

    CREATE OR REPLACE TABLE final_temp_table AS
      WITH chunked_data AS (
        SELECT
            patient_id,
            chunk.value AS chunk_text,
            chunk.index AS chunk_index
          FROM
            patients,
            LATERAL FLATTEN(
                input => SNOWFLAKE.CORTEX.SPLIT_TEXT_RECURSIVE_CHARACTER(
                    patient_notes,
                    'none',
                    1000
                    )
                ) AS chunk
          WHERE
            patient_notes IS NOT NULL
            AND LENGTH(patient_notes) > 0
        ),
      redacted_chunks AS (
          SELECT
              patient_id,
              chunk_index,
              chunk_text,
              TO_VARIANT(results:value) AS redacted_chunk,
              TO_VARIANT(results:error) AS error_string
            FROM (
              SELECT
                  patient_id,
                  chunk_index,
                  chunk_text,
                  AI_REDACT(chunk_text,TRUE) AS results
                FROM
                  chunked_data
            )
      ),
      final AS (
          SELECT
              chunk_text AS original,
              IFF(error_string IS NOT NULL, chunk_text, redacted_chunk) AS redacted_text,
              patient_id,
              chunk_index
            FROM
              redacted_chunks
      )
      SELECT * FROM final;
    
    Copy
  3. 結果をクエリします。

    SELECT
        patient_id,
        LISTAGG(redacted_text, '') WITHIN GROUP (ORDER BY chunk_index) AS full_output
      FROM final_temp_table
      GROUP BY patient_id;
    
    Copy

検出と選択的編集の例

基本的な検出の例

次の例では、入力を編集せずに、検出された各PIIインスタンスのカテゴリ、場所、およびテキストを特定して返します。

SELECT AI_REDACT(
    input => 'My old manager, Washington, used to live in Washington. His first name was Mike.',
    return_error_details => FALSE,
    mode => 'detect'
    );
Copy

基本的な検出の出力:

{
  "spans": [
    {
      "category": "NAME",
      "end": 26,
      "start": 16,
      "text": "Washington"
    },
    {
      "category": "ADDRESS",
      "end": 54,
      "start": 44,
      "text": "Washington"
    },
    {
      "category": "NAME",
      "end": 79,
      "start": 75,
      "text": "Mike"
    }
  ]
}

許可リストを使用したエンドツーエンドの例

次の例は、``detect``モードと許可リストを使用した選択的編集ワークフローを示しています。ステージングされたファイルから保持する名前のリストをロードし、``detect``モードでAI_REDACTを使用してPIIの場所を特定し、許可リストにないPIIのみを編集するPython UDFにその結果を渡します。

  1. ステージから仮テーブルにリストをロードすることにより、値の許可リストを保持します。

    CREATE OR REPLACE TEMP TABLE string_list (value STRING);
    
    COPY INTO string_list
      FROM @mystage/allowlist.txt
      FILE_FORMAT = (
        TYPE = 'CSV'
        RECORD_DELIMITER = '\n'
        FIELD_DELIMITER = '\t'   -- any char NOT in file
        TRIM_SPACE = TRUE
        SKIP_HEADER = 0
        );
    
    Copy
  2. 許可リストテーブルを表示します。

    SELECT * FROM string_list;
    
    Copy

    許可リストテーブルの出力:

    VALUE
    Mike
    David
    
  3. 許可リストに基づいてPIIを選択的に編集するPython UDFを作成します。

    CREATE OR REPLACE FUNCTION redact_spans_with_allowlist(
      SPAN_DATA VARIANT,
      ALLOWLIST ARRAY,
      ORIGINAL_TEXT STRING
      )
      RETURNS STRING
      LANGUAGE PYTHON
      RUNTIME_VERSION = '3.8'
      HANDLER = 'redact_text'
      AS
      $$
      def redact_text(span_data, allowlist, original_text):
          spans = span_data.get('spans', [])
          # Sort descending to maintain index integrity
          sorted_spans = sorted(spans, key=lambda x: x['start'], reverse=True)
    
          result = original_text
    
          for span in sorted_spans:
              text_val = span.get('text')
              if text_val in allowlist:
                  continue
    
              start, end = span['start'], span['end']
              label = f"[{span['category']}]"
    
              # Splice the string
              result = result[:start] + label + result[end:]
    
          return result
      $$;
    
    Copy
  4. UDFをテストします。

    SELECT redact_spans_with_allowlist(
      PARSE_JSON('{"spans": [{"category": "NAME", "end": 26, "start": 16, "text": "Washington"}, {"category": "NAME", "end": 79, "start": 75, "text": "Mike"}]}'),
      ARRAY_CONSTRUCT('Washington'), -- This will NOT be redacted
      'Hello, my name is Washington and his is Mike.'
      );
    
    Copy
  5. ``detect``モードでAI_REDACTを実行します。

    CREATE OR REPLACE TABLE raw (message TEXT);
    
    INSERT INTO raw (message) VALUES
      ('My old manager, Washington, used to live in Washington. His first name was Mike.');
    
    SELECT
        t.message AS message,
        AI_REDACT(input=>t.message, return_error_details=>FALSE, mode=>'detect') AS spans,
        redact_spans_with_allowlist(spans, l.str_list, message) AS result
      FROM raw t
        CROSS JOIN (
          SELECT ARRAY_AGG(value) AS str_list
            FROM string_list
          ) l;
    
    Copy

許可リストを使用したエンドツーエンドの例の出力:

MESSAGE

SPANS

RESULT

私の前のマネージャー、ワシントンはワシントンに住んでいました。ファーストネームはマイクでした。

{
  "spans": [
    {"category": "NAME",
    "end": 26,
    "start": 16,
    "text": "Washington"
    },
    {"category": "ADDRESS",
    "end": 54,
    "start": 44,
    "text": "Washington"
    },
    {"category": "NAME",
    "end": 79,
    "start": 75,
    "text": "Mike"
    }
  ]
}
Copy

私の前のマネージャー、[NAME]は[ADDRESS]に住んでいました。ファーストネームはマイクでした。