本页介绍了如何执行混合全文和非文本数据的搜索。
执行混合全文和非文本搜索
搜索索引支持全文、完全匹配、数值列和 JSON/JSONB 列。您可以将文本条件和非文本条件组合在 WHERE 子句中,类似于多列搜索查询。查询优化器会尝试使用搜索索引优化非文本谓词。如果无法做到这一点,Spanner 会针对与搜索索引匹配的每行评估条件。未存储在搜索索引中的引用列会从基表中提取。
请参考以下示例:
GoogleSQL
CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Rating FLOAT64,
  Genres ARRAY<STRING(MAX)>,
  Likes INT64,
  Cover BYTES(MAX),
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
  Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN,
  Genres_Tokens TOKENLIST AS (TOKEN(Genres)) HIDDEN
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex
ON Albums(Title_Tokens, Rating_Tokens, Genres_Tokens)
STORING (Likes);
PostgreSQL
Spanner PostgreSQL 支持具有以下限制:
- spanner.tokenize_number函数仅支持- bigint类型。
- spanner.token不支持对数组进行词元化处理。
CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  rating bigint,
  genres character varying NOT NULL,
  likes bigint,
  cover bytea,
  title_tokens spanner.tokenlist AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
  rating_tokens spanner.tokenlist AS (spanner.tokenize_number(rating)) VIRTUAL HIDDEN,
  genres_tokens spanner.tokenlist AS (spanner.token(genres)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex
ON albums(title_tokens, rating_tokens, genres_tokens)
INCLUDE (likes);
对此表执行查询的行为包括:
- Rating和- Genres包含在搜索索引中。Spanner 使用搜索索引发布列表加快满足条件的速度。- ARRAY_INCLUDES_ANY、- ARRAY_INCLUDES_ALL是 GoogleSQL 函数,PostgreSQL 方言不支持。- SELECT Album FROM Albums WHERE Rating > 4 AND ARRAY_INCLUDES_ANY(Genres, ['jazz'])
- 查询可以以任何方式组合连词、析取和取反,包括混合使用全文本和非文本谓词。此查询完全由搜索索引加速。 - SELECT Album FROM Albums WHERE (SEARCH(Title_Tokens, 'car') OR Rating > 4) AND NOT ARRAY_INCLUDES_ANY(Genres, ['jazz'])
- Likes存储在索引中,但架构不会请求 Spanner 为其可能的值构建 token 索引。因此,- Title上的全文谓词和- Rating上的非文本谓词会加速,但- Likes上的谓词不会加速。在 Spanner 中,查询会提取- Title中包含“car”一词且评分超过 4 的所有文档,然后过滤掉没有至少 1000 个点赞的文档。如果几乎所有专辑的标题中都包含“car”一词,并且几乎所有专辑的评分都为 5 分,但只有少数专辑的点赞数为 1000,那么此查询会使用大量资源。在这种情况下,将- Likes与- Rating类似地编入索引可节省资源。- GoogleSQL- SELECT Album FROM Albums WHERE SEARCH(Title_Tokens, 'car') AND Rating > 4 AND Likes >= 1000- PostgreSQL- SELECT album FROM albums WHERE spanner.search(title_tokens, 'car') AND rating > 4 AND likes >= 1000
- Cover不会存储在索引中。以下查询会在- AlbumsIndex和- Albums之间执行后向联接,以便为所有匹配的专辑提取- Cover。- GoogleSQL- SELECT AlbumId, Cover FROM Albums WHERE SEARCH(Title_Tokens, 'car') AND Rating > 4- PostgreSQL- SELECT albumid, cover FROM albums WHERE spanner.search(title_tokens, 'car') AND rating > 4