使用文本分析器

CREATE SEARCH INDEX DDL 语句SEARCH 函数TEXT_ANALYZE 函数支持高级文本分析器配置选项。通过了解 BigQuery 的文本分析器及其选项,您可以优化搜索体验。

本文档简要介绍 BigQuery 中提供的不同文本分析器及其配置选项,以及文本分析器如何与 BigQuery 中的搜索搭配使用。如需详细了解文本分析器语法,请参阅文本分析

文本分析器

BigQuery 支持以下文本分析器:

  • NO_OP_ANALYZER
  • LOG_ANALYZER
  • PATTERN_ANALYZER

NO_OP_ANALYZER

在预处理完您希望完全匹配的数据后,请使用 NO_OP_ANALYZER。系统不会对文本应用词元化或标准化。由于此分析器不执行词法单元化或标准化,因此不接受任何配置。如需详细了解 NO_OP_ANALYZER,请参阅 NO_OP_ANALYZER

LOG_ANALYZER

LOG_ANALYZER 通过以下方式修改数据:

  • 文本将变成小写。
  • 大于 127 的 ASCII 值将保持不变。

  • 文本由以下分隔符拆分为称为“词法单元”的单个术语:

    [ ] < > ( ) { } | ! ; , ' " * & ? + / : = @ . - $ % \ _ \n \r \s \t %21 %26
    %2526 %3B %3b %7C %7c %20 %2B %2b %3D %3d %2520 %5D %5d %5B %5b %3A %3a %0A
    %0a %2C %2c %28 %29
    

    如果您不想使用默认分隔符,则可以指定要用作文本分析器选项的分隔符。通过 LOG_ANALYZER,您可以配置特定的分隔符和令牌过滤器,以便更好地控制搜索结果。如需详细了解使用 LOG_ANALYZER 时可用的特定配置选项,请参阅 delimiters 分析器选项token_filters 分析器选项。

PATTERN_ANALYZER

PATTERN_ANALYZER 文本分析器使用正则表达式从文本中提取词法单元。与 PATTERN_ANALYZER 搭配使用的正则表达式引擎和语法为 RE2PATTERN_ANALYZER 按以下顺序对模式进行词法单元化处理:

  1. 它会找到与字符串中的模式(从左侧起)匹配的第一个子字符串。这是要包含在输出中的词法单元。
  2. 它会从输入字符串中移除所有内容(直到第 1 步中发现的子字符串结尾)。
  3. 它会重复该过程,直到字符串为空。

下表提供了 PATTERN_ANALYZER 词法单元提取示例:

模式 输入文本 输出令牌
ab ababab
  • ab
ab abacad
  • ab
[a-z]{2} abacad
  • ab
  • ac
  • ad
aaa aaaaa
  • aaa
[a-z]/ a/b/c/d/e
  • a/
  • b/
  • c/
  • d/
/[^/]+/ aa/bb/cc
  • /bb/
[0-9]+ abc
(?:/?)[a-z] /abc
  • /abc
(?:/)[a-z] /abc
  • /abc
(?:[0-9]abc){3}(?:[a-z]000){2} 7abc7abc7abcx000y000
  • 7abc7abc7abcx000y000
".+" "cats" 和 "dogs"
  • "cats" 和 "dogs"


请注意,使用贪婪限定符 + 会匹配文本中可能的最长字符串,导致将“cats”和“dogs”作为文本中的词法单元进行提取。
".+?" "cats" 和 "dogs"
  • "cats"
  • "dogs"


请注意,使用延迟限定符 +? 会使正则表达式与文本中可能的最短字符串匹配,导致 '"cats"' 和 '"dogs"' 作为文本中的 2 个单独词法单元进行提取。

SEARCH 函数搭配使用时,使用 PATTERN_ANALYZER 文本分析器可让您更好地控制从文本中提取的词法单元。下表显示了不同的模式和结果如何生成不同的 SEARCH 结果:

模式 查询 文本 文本中的词法单元 SEARCH(文本、查询) 说明
abc abcdef abcghi
  • abcghi
TRUE ['abcghi'] 中的 'abc'
cd[a-z] abcdef abcghi
  • abcghi
FALSE ['abcghi'] 中的 'cde'
[a-z]/ a/b/ a/b/c/d/
  • a/
  • b/
  • c/
  • d/
TRUE ['a/', 'b/', 'c/', 'd/'] 中的 'a/' 和 ['a/', 'b/', 'c/', 'd/'] 中的 'b/'
/[^/]+/ aa/bb/ aa/bb/cc/
  • /bb/
TRUE ['/bb/'] 中的 '/bb/'
/[^/]+/ bb aa/bb/cc/
  • /bb/
错误 未在查询字词中找到匹配项
[0-9]+ abc abc123 错误 未在查询字词中找到匹配项
[0-9]+ `abc` abc123 错误 在查询字词中找不到匹配项

将反引号匹配为反引号,而不是特殊字符。
[a-z][a-z0-9]*@google\.com This is my email: test@google.com test@google.com
  • test@google.com
TRUE 'test@google.com' 中的 'test@google.com'
abc abc\ abc abc
  • abc
TRUE ['abc'] 中的 'abc'

请注意,'abc abc' 是一个由搜索查询解析器解析后的单个子查询,因为空间已转义。
(?i)(?:Abc)(无标准化) aBcd Abc
  • Abc
FALSE ['Abc'] 中的 'aBc'
(?i)(?:Abc)

标准化:
lower_case = true
aBcd Abc
  • abc
TRUE ['abc'] 中的 'abc'
(?:/?)abc bc/abc /abc/abc/
  • /abc
TRUE ['/abc'] 中的 '/abc'
(?:/?)abc abc d/abc
  • /abc
FALSE ['/abc'] 中的 'abc'
".+" "cats" "cats" 和 "dogs"
  • "cats" 和 "dogs"
FALSE ['"cats" and "dogs"] 中的 '"cats"'

请注意,使用贪婪限定符 + 会让正则表达式匹配文本中可能的最长字符串,导致将 '"cats" 和 "dogs"' 作为文本中的词法单元进行提取。
".+?" "cats" "cats" 和 "dogs"
  • "cats"
  • "dogs"
TRUE ['"cats" and "dogs"] 中的 '"cats"'

请注意,使用延迟限定符 +? 会使正则表达式与文本中尽可能短的字符串匹配,导致 '"cats"'、'"dogs"' 在文本中被提取为 2 个单独的词法单元。

示例

以下示例演示如何通过自定义选项使用文本分析来创建搜索索引、提取词法单元并返回搜索结果。

LOG_ANALYZER 与 NFKC ICU 标准化和停止字词搭配使用

以下示例使用 NFKC ICU 标准化和停止字词来配置 LOG_ANALYZER 选项。该示例假定以下数据表已填充数据:

CREATE TABLE dataset.data_table(
  text_data STRING
);

如需使用 NFKC ICU 标准化和停止字词列表创建搜索索引,请在 CREATE SEARCH INDEX DDL 语句analyzer_options 选项中创建 JSON 格式的字符串。如需查看使用 LOG_ANALYZER 创建搜索索引时可用的选项的完整列表,请参阅 LOG_ANALYZER。在本示例中,我们的停止字词是 "the", "of", "and", "for"

CREATE OR REPLACE SEARCH INDEX `my_index` ON `dataset.data_table`(ALL COLUMNS) OPTIONS(
  analyzer='PATTERN_ANALYZER',
  analyzer_options= '''{
    "token_filters": [
      {
        "normalizer": {
          "mode": "ICU_NORMALIZE",
          "icu_normalize_mode": "NFKC",
          "icu_case_folding": true
        }
      },
      { "stop_words": ["the", "of", "and", "for"] }
    ]
  }''');

根据上例,下表介绍了 text_data 各种值的词法单元提取。请注意,在本文档中,双问号字符 () 已斜体处理,以区分两个问号 (??):

数据文本 索引的词法单元 说明
The Quick Brown Fox ["quick", "brown", "fox"] LOG_ANALYZER 词法单元化会生成词法单元 ["The", "Quick", "Brown", "Fox"]。

接下来,设为 icu_case_folding = true 的 ICU 标准化会将词法单元小写,以生成 ["the", "quick", "brown", "fox"]

最后,停用字词过滤条件会从列表中移除“the”。
The Ⓠuick Ⓑrown Ⓕox ["quick", "brown", "fox"] LOG_ANALYZER 词法单元化会生成词法单元 ["The", "Ⓠuick", "Ⓑrown", "Ⓕox"]。

接下来,设为 icu_case_folding = true 的 NFKC ICU 标准化会将词法单元小写,以生成 ["the", "quick", "brown", "fox"]

最后,停用字词过滤条件会从列表中移除“the”。
ⓆuickⒻox ["quick??fox"] LOG_ANALYZER 词法单元化会生成词法单元 ["The", "ⓆuickⒻox"]。

接下来,设为 icu_case_folding = true 的 NFKC ICU 标准化并将令牌生成 ["quick??fox"]。请注意,双问号 Unicode 已标准化为 2 个问号 ASCII 字符。

最后,停止字词过滤条件不执行任何操作,因为过滤条件列表中没有任何词法单元。

现在搜索索引已创建,接下来您可以使用 SEARCH 函数通过搜索索引中指定的相同分析器配置来搜索表。请注意,如果 SEARCH 函数中的分析器配置与搜索索引的配置不匹配,则不会使用搜索索引。使用以下查询:

SELECT
  SEARCH(
  analyzer => 'LOG_ANALYZER',
  analyzer_options => '''{
    "token_filters": [
      {
        "normalizer": {
          "mode": "ICU_NORMALIZE",
          "icu_normalize_mode": "NFKC",
          "icu_case_folding": true
        }
      },
      {
        "stop_words": ["the", "of", "and", "for"]
      }
    ]
  }''')

替换以下内容:

  • search_query:您要搜索的文本。

下表根据不同的搜索文本和不同的 search_query 值演示了各种结果:

text_data search_query 结果 说明
The Quick Brown Fox "Ⓠuick" TRUE 从文本中提取的词法单元最终列表为 ["quick", "brown", "fox"]。
从文本查询中提取的词法单元的最终列表为 ["quick"]。

列表查询标记都可以在文本词法单元中找到。
The Ⓠuick Ⓑrown Ⓕox "quick" TRUE 从文本中提取的词法单元最终列表为 ["quick", "brown", "fox"]。
从文本查询中提取的词法单元的最终列表为 ["quick"]。

列表查询标记都可以在文本词法单元中找到。
ⓆuickⒻox "quick" FALSE 从文本中提取的词法单元的最终列表为 ["quick??fox"]。

从文本查询中提取的词法单元的最终列表为 ["quick"]。

“quick”不在文本的词法单元列表中。
ⓆuickⒻox "quickfox" TRUE 从文本中提取的词法单元的最终列表为 ["quick??fox"]。

从文本查询中提取的词法单元的最终列表为 ["quick??fox"]。

“quick??fox”位于文本的词法单元列表中。
ⓆuickⒻox "`quickfox`" FALSE LOG_ANALYZER 中,反引号需要完全匹配文本。

PATTERN_ANALYZER,用于具有停止字词的 IPv4 搜索

以下示例将 PATTERN_ANALYZER 文本分析器配置为搜索特定模式,同时过滤特定停止字词。在此示例中,模式与 IPv4 地址匹配,并忽略 localhost 值 (127.0.0.1)。

此示例假定下表填充了数据:

CREATE TABLE dataset.data_table(
  text_data STRING
);

如需创建搜索索引 pattern 选项和停止字词列表,请在 CREATE SEARCH INDEX DDL 语句analyzer_options 选项中创建 JSON 格式的字符串 如需查看使用 PATTERN_ANALYZER 创建搜索索引时可用的选项的完整列表,请参阅 PATTERN_ANALYZER。在本示例中,我们的停止字词是 localhost 地址 127.0.0.1

CREATE SEARCH INDEX my_index
ON dataset.data_table(text_data)
OPTIONS (analyzer = 'PATTERN_ANALYZER', analyzer_options = '''{
  "patterns": [
    "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
  ],
  "token_filters": [
    {
      "stop_words": [
        "127.0.0.1"
      ]
    }
  ]
}'''
);

将正则表达式与 analyzer_options 搭配使用时,请包含三个前导 \ 符号,以正确转义包含 \ 符号的正则表达式,例如 \d\b

下表介绍了 text_data 各种值的词法单元化选项

数据文本 索引的词法单元 说明
abc192.168.1.1def 172.217.20.142 ["192.168.1.1", "172.217.20.142"] 即使地址和文本之间没有空格,IPv4 模式也会捕获 IPv4 地址。
104.24.12.10abc 127.0.0.1 ["104.24.12.10"] “127.0.0.1”已被滤除,因为它位于停止字词列表中。

搜索索引现已创建,您可以使用 SEARCH 函数根据 analyzer_options 中指定的词法单元化来搜索表。使用以下查询:

SELECT
  SEARCH(dataset.data_table.text_data
  "search_data",
  analyzer => 'PATTERN_ANALYZER',
  analyzer_options => '''{
    "patterns": [
      "(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)[.]){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
      ],
    "token_filters": [
      {
        "stop_words": [
          "127.0.0.1"
        ]
      }
    ]
  }'''
);

替换以下内容:

  • search_query:您要搜索的文本。

下表根据不同的搜索文本和不同的 search_query 值演示了各种结果:

text_data search_query 结果 说明
128.0.0.2 "127.0.0.1" 错误 查询中没有搜索词法单元。

查询会经过文本分析器,它会过滤掉“127.0.0.1”词法单元。
abc192.168.1.1def 172.217.20.142 "192.168.1.1abc" TRUE 从查询中提取的词法单元列表为 ["192.168.1.1"]。

从文本中提取的词法单元列表为 ["192.168.1.1", "172.217.20.142"]。
abc192.168.1.1def 172.217.20.142 "`192.168.1.1`" TRUE 从查询中提取的词法单元列表为 ["192.168.1.1"]。

从文本中提取的词法单元列表为 ["192.168.1.1", "172.217.20.142"]。

请注意,反引号被视为 PATTERN_ANALYZER 的常规字符。

后续步骤