混合使用全文本查询和非文本查询

本页介绍了如何执行混合全文和非文本数据的搜索。

搜索索引支持全文、完全匹配、数值列和 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);

对此表执行查询的行为包括:

  • RatingGenres 包含在搜索索引中。Spanner 使用搜索索引发布列表加快满足条件的速度。ARRAY_INCLUDES_ANYARRAY_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,那么此查询会使用大量资源。在这种情况下,将 LikesRating 类似地编入索引可节省资源。

    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 不会存储在索引中。以下查询会在 AlbumsIndexAlbums 之间执行后向联接,以便为所有匹配的专辑提取 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
    

后续步骤