词法单元化

本页面介绍了如何为表添加词元化。必须进行词元化,才能创建搜索索引中使用的token。

词元化是将值转换为token的过程。您用于对文档进行词元化的方法决定了用户对文档执行搜索的类型和效率。

Spanner 为自然语言文本、子字符串、逐字文本、数字和布尔值提供了词元化器。数据库架构使用与列所需的搜索类型相匹配的词元化器。词元化器具有以下特征:

  • 每个词元化器都是一个 SQL 函数,用于获取输入(例如字符串或数字)和用于指定其他选项的命名参数。
  • 词元化器输出 TOKENLIST

例如,文本字符串 The quick brown fox jumps over the lazy dog 会被词元化为 [the,quick,brown,fox,jumps,over,the,lazy,dog]。HTML 字符串 The <b>apple</b> is <i>red</i> 被词元化为 [the,apple,is,red]

token具有以下特性:

  • token存储在使用 TOKENLIST 数据类型的列中。
  • 每个token都存储为字节序列,并包含一组可选的关联属性。例如,在全文应用中,token通常是文本文档中的单个字词。
  • 在对 HTML 值进行词元化处理时,Spanner 会生成一些属性,用于指示文档中某个token的重要程度。Spanner 会使用这些属性来进行评分,以提升更突出的字词(例如标题)。

词元化器

Spanner 支持以下词元化器函数:

  • 全文词元化器 (TOKENIZE_FULLTEXT) 会为自然语言查询生成全字token。

    示例

    以下两个函数

    GoogleSQL

    TOKENIZE_FULLTEXT("Yellow apple")
    TOKENIZE_FULLTEXT("Yellow <b>apple</b>", content_type=>"text/html")
    

    PostgreSQL

    此示例使用 spanner.tokenize_fulltext

    spanner.tokenize_fulltext("Yellow apple")
    spanner.tokenize_fulltext('Yellow <b>apple</b>', context_type=>'text/html')
    

    生成相同的token:[yellow,apple]

  • 子字符串词元化器 (TOKENIZE_SUBSTRING) 会为每个字词的每个 N 元语法生成token。用于查找文本中的字词子字符串。

    示例

    GoogleSQL

    TOKENIZE_SUBSTRING('hello world', ngram_size_min=>4, ngram_size_max=>6)
    

    PostgreSQL

    此示例使用 spanner.tokenize_substring

    spanner.tokenize_substring('hello world', ngram_size_min=>4, ngram_size_max=>6)
    

    生成以下token:[ello,hell,hello,orld,worl,world]

  • N 元语法词元化器 (TOKENIZE_NGRAMS) 会根据输入内容生成 N 元语法(不会将输入内容拆分为单独的字词)。它用于加快正则表达式谓词的速度。

    示例

    以下函数:

    GoogleSQL

    TOKENIZE_NGRAMS("Big Time", ngram_size_min=>4, ngram_size_max=>4)
    

    PostgreSQL

    此示例使用 spanner.tokenize_ngrams

    spanner.tokenize_ngrams('big time', ngram_size_min=>4, ngram_size_max=>4)
    

    生成以下token:["Big ","ig T","g Ti"," Tim", "Time"]

  • 完全匹配词元化器 (TOKENTOKENIZE_BOOL) 用于查找某个列中包含特定值的行。例如,对商品清单编制索引的应用可能希望搜索特定品牌和颜色的商品。

    示例

    以下函数:

    GoogleSQL

    TOKEN("hello")
    TOKEN(["hello", "world"])
    

    PostgreSQL

    此示例使用 spanner.token

    spanner.token('hello')
    

    生成以下token:[hello]

    以下函数:

    GoogleSQL

    TOKENIZE_BOOL(true)
    

    PostgreSQL

    此示例使用 spanner.tokenize_bool

    spanner.tokenize_bool(true)
    

    生成以下token:[y]

  • 数字词元化器 (TOKENIZE_NUMBER) 用于生成一组加快数字比较搜索速度的 token。对于相等条件,token是数字本身。对于范围条件(如 rating >= 3.5),token集会更为复杂。

    示例

    以下函数语句:

    GoogleSQL

    TOKENIZE_NUMBER(42, comparison_type=>'equality')
    TOKENIZE_NUMBER(42, comparison_type=>'all', granularity=>10, min=>1, max=>100)
    

    PostgreSQL

    此示例使用 spanner.tokenize_number

    spanner.tokenize_number(42, comparison_type=>'equality')
    spanner.tokenize_number(42, comparison_type=>'all', granularity=>10, min=>1, max=>100)
    

    分别生成以下token:"==42""==42""[1,75]""[36, 45]""[36,55]""[36, 75]"

  • JSON 和 JSONB 词元化器 (TOKENIZE_JSONTOKENIZE_JSONB)用于生成一组token,以加快 JSON 包含关系和键存在谓词的速度,例如 doc[@key] IS NOT NULL (GoogleSQL) 或 doc ? 'key' (PostgreSQL)。

词元化函数通常用于生成的列表达式。这些列被定义为 HIDDEN,因此不会包含在 SELECT * 查询结果中。

以下示例使用全文本词元化器和数字词元化器来创建一个用于存储音乐专辑名称和评分的数据库。DDL 语句会执行以下两项操作:

  1. 定义数据列 AlbumTitleRating
  2. 定义 AlbumTitle_TokensAlbumRating_Tokens。这些 TOKENLIST 列会对数据列中的值进行词元化处理,以便 Spanner 将其编入索引。

    GoogleSQL

    CREATE TABLE Albums (
      AlbumId STRING(MAX) NOT NULL,
      AlbumTitle STRING(MAX),
      Rating FLOAT64,
      AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
      Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN
    ) PRIMARY KEY(AlbumId);
    

    PostgreSQL

    CREATE TABLE albums (
      albumid character varying NOT NULL,
      albumtitle character varying,
      albumtitle_Tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
    PRIMARY KEY(albumid));
    

每当修改基础值时,AlbumTitle_TokensRating_Tokens 都会自动更新。

对纯文本或 HTML 内容进行词元化处理

文本词元化支持纯文本和 HTML 内容类型。使用 Spanner TOKENIZE_FULLTEXT 函数创建token。然后,使用 CREATE SEARCH INDEX DDL 语句生成搜索索引。

例如,以下 CREATE TABLE DDL 语句使用 TOKENIZE_FULLTEXT 函数从 Albums 表中的 AlbumTitles 创建token。CREATE SEARCH INDEX DDL 语句会使用新的 AlbumTitles_Tokens 创建搜索索引。

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  AlbumTitle STRING(MAX),
  AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(AlbumTitle_Tokens)

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  albumtitle character varying,
  albumtitle_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(albumtitle_tokens)

词元化过程使用以下规则:

  • 词元化不包括词干提取或更正拼写错误的单词。例如,在“A cat was looking at a group of cats”这样的句子中,“cat”与“cats”是分开编入索引的。与在写入期间对token进行标准化的其他搜索引擎相比,Spanner 提供了一种选项,可将搜索查询扩展为包含不同形式的字词。如需了解详情,请参阅增强型查询模式
  • 搜索索引中包含无效搜索字词(例如“a”)。
  • 全文搜索始终不区分大小写。词元化过程会将所有token转换为小写。

词元化过程会跟踪原始文本中每个token的位置。这些位置稍后用于匹配短语。这些位置会与 docid 一起存储在搜索索引中。

Google 会继续改进词元化算法。在某些情况下,这可能会导致字符串在将来的词元化方式与现在的词元化方式不同。我们预计此类情况非常罕见。例如,如果中文、日语和韩语 (CJK) 语言细分功能有所改进,您就可以看到这种情况。

content_type 参数用于指定内容格式是使用纯文本还是 HTML。使用以下设置来设置 content_type

  • 对于文本词元化,请将 content_type 参数设置为“text/plain”。这是默认设置。
  • 对于 HTML 词元化,请将 content_type 参数设置为 "text/html。如果不使用此参数,HTML 标记会被视为标点符号。在 HTML 模式下,Spanner 会使用启发法来推断文本在网页上的突出程度。例如,文本是否位于标题中或其字体大小。 支持的 HTML 属性包括 smallmediumlargetitle 和“link”。与位置一样,该属性会与搜索索引中的token一起存储。词元化过程不会为任何 HTML 标记创建token。

token属性不会影响匹配或 SEARCHSEARCH_SUBSTRING 函数的结果。它们仅用于排名

以下示例展示了如何对文本进行词元化处理:

GoogleSQL

CREATE TABLE T (
  ...
  Text STRING(MAX),
  Html STRING(MAX),
  Text_Tokens TOKENLIST
    AS (TOKENIZE_FULLTEXT(Text, content_type=>"text/plain")) HIDDEN,
  Html_Tokens TOKENLIST
    AS (TOKENIZE_FULLTEXT(Html, content_type=>"text/html")) HIDDEN
) PRIMARY KEY(...);

PostgreSQL

CREATE TABLE t (
  ...
  text character varying,
  html character varying,
  text_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(text, content_type=>"text/plain")) VIRTUAL HIDDEN,
  html_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(html, content_type=>'type/html')) VIRTUAL HIDDEN,
PRIMARY KEY(...));

使用 language_tag 参数对语言检测进行优化

默认情况下,词元化过程会自动检测输入语言。在已知输入语言的情况下,可以使用 language_tag 参数来优化此行为:

GoogleSQL

AlbumTitle_Tokens TOKENLIST
  AS (TOKENIZE_FULLTEXT(AlbumTitle, language_tag=>"en-us")) HIDDEN

PostgreSQL

albumtitle_tokens spanner.tokenlist
      GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle, language_tag=>'en-us')) VIRTUAL HIDDEN

大多数应用会将 language_tag 参数保留为未指定状态,而依赖于自动语言检测。中文、韩语和日语等亚洲语言的分词不需要设置词元化语言。

以下示例展示了 language_tag 影响词元化的情形:

词元化函数 生成的token
TOKENIZE_FULLTEXT("A tout pourquoi il y a un parce que") [a, tout, pourquoi, il, ya, un, parce, que]
TOKENIZE_FULLTEXT("A tout pourquoi il y a un parce que", \ language_tag=>"fr") [a, tout, pourquoi, il, y, a, un, parce, que]
TOKENIZE_FULLTEXT("旅 行") 两个token:[旅, 行]
TOKENIZE_FULLTEXT("旅 行", language_tag=>"zh") 一个token:[旅行]

后续步骤