[[["わかりやすい","easyToUnderstand","thumb-up"],["問題の解決に役立った","solvedMyProblem","thumb-up"],["その他","otherUp","thumb-up"]],[["わかりにくい","hardToUnderstand","thumb-down"],["情報またはサンプルコードが不正確","incorrectInformationOrSampleCode","thumb-down"],["必要な情報 / サンプルがない","missingTheInformationSamplesINeed","thumb-down"],["翻訳に関する問題","translationIssue","thumb-down"],["その他","otherDown","thumb-down"]],["最終更新日 2025-09-05 UTC。"],[],[],null,["# Mix full-text and non-text queries\n\n| **Note:** This feature is available with the Spanner Enterprise edition and Enterprise Plus edition. For more information, see the [Spanner editions overview](/spanner/docs/editions-overview).\n\n\u003cbr /\u003e\n\nThis page describes how to perform a search that mixes full-text and non-text\ndata.\n\nPerform a mixed full-text and non-text search\n---------------------------------------------\n\n[Search indexes](/spanner/docs/full-text-search/search-indexes) support\nfull-text, exact match, numeric columns, and JSON/JSONB columns. You can combine\ntext and non-text conditions in the `WHERE` clause similarly to multi-column\nsearch queries. The query optimizer tries to optimize non-text predicates with a\nsearch index. If that's not possible, Spanner evaluates the\ncondition for every row that matches the search index. Referenced columns not\nstored in the search index are fetched from the base table.\n\nConsider the following example: \n\n### GoogleSQL\n\n CREATE TABLE Albums (\n AlbumId STRING(MAX) NOT NULL,\n Title STRING(MAX),\n Rating FLOAT64,\n Genres ARRAY\u003cSTRING(MAX)\u003e,\n Likes INT64,\n Cover BYTES(MAX),\n Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,\n Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN,\n Genres_Tokens TOKENLIST AS (TOKEN(Genres)) HIDDEN\n ) PRIMARY KEY(AlbumId);\n\n CREATE SEARCH INDEX AlbumsIndex\n ON Albums(Title_Tokens, Rating_Tokens, Genres_Tokens)\n STORING (Likes);\n\n### PostgreSQL\n\nSpanner PostgreSQL support has the following\nlimitations:\n\n- `spanner.tokenize_number` function only supports the `bigint` type.\n- `spanner.token` doesn't support tokenizing arrays.\n\n CREATE TABLE albums (\n albumid character varying NOT NULL,\n title character varying,\n rating bigint,\n genres character varying NOT NULL,\n likes bigint,\n cover bytea,\n title_tokens spanner.tokenlist AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,\n rating_tokens spanner.tokenlist AS (spanner.tokenize_number(rating)) VIRTUAL HIDDEN,\n genres_tokens spanner.tokenlist AS (spanner.token(genres)) VIRTUAL HIDDEN,\n PRIMARY KEY(albumid));\n\n CREATE SEARCH INDEX albumsindex\n ON albums(title_tokens, rating_tokens, genres_tokens)\n INCLUDE (likes);\n\nThe behavior of queries on this table include the following:\n\n- `Rating` and `Genres` are included in the search index.\n Spanner accelerates conditions using search index posting\n lists. `ARRAY_INCLUDES_ANY`, `ARRAY_INCLUDES_ALL` are GoogleSQL\n functions and are not supported for PostgreSQL dialect.\n\n SELECT Album\n FROM Albums\n WHERE Rating \u003e 4\n AND ARRAY_INCLUDES_ANY(Genres, ['jazz'])\n\n- The query can combine conjunctions, disjunctions, and negations in any way,\n including mixing full-text and non-text predicates. This query is fully\n accelerated by the search index.\n\n SELECT Album\n FROM Albums\n WHERE (SEARCH(Title_Tokens, 'car')\n OR Rating \u003e 4)\n AND NOT ARRAY_INCLUDES_ANY(Genres, ['jazz'])\n\n- `Likes` is stored in the index, but the schema doesn't request\n Spanner to build a token index for its possible values.\n Therefore, the full-text predicate on `Title` and non-text predicate on\n `Rating` is accelerated, but the predicate on `Likes` isn't. In\n Spanner, the query fetches all documents with the term \"car\"\n in the `Title` and a rating more than 4, then it filters documents that\n don't have at least 1000 likes. This query uses a lot of resources if almost\n all albums have the term \"car\" in their title and almost all of them have a\n rating of 5, but few albums have 1000 likes. In such cases, indexing\n `Likes` similarly to `Rating` saves resources.\n\n ### GoogleSQL\n\n SELECT Album\n FROM Albums\n WHERE SEARCH(Title_Tokens, 'car')\n AND Rating \u003e 4\n AND Likes \u003e= 1000\n\n ### PostgreSQL\n\n SELECT album\n FROM albums\n WHERE spanner.search(title_tokens, 'car')\n AND rating \u003e 4\n AND likes \u003e= 1000\n\n- `Cover` isn't stored in the index. The following query does a\n [back join](/spanner/docs/query-execution-plans#index_and_back_join_queries)\n between `AlbumsIndex` and `Albums` to fetch `Cover` for all matching albums.\n\n ### GoogleSQL\n\n SELECT AlbumId, Cover\n FROM Albums\n WHERE SEARCH(Title_Tokens, 'car')\n AND Rating \u003e 4\n\n ### PostgreSQL\n\n SELECT albumid, cover\n FROM albums\n WHERE spanner.search(title_tokens, 'car')\n AND rating \u003e 4\n\nWhat's next\n-----------\n\n- Learn about [full-text search queries](/spanner/docs/full-text-search/query-overview).\n- Learn how to [rank search results](/spanner/docs/full-text-search/ranked-search).\n- Learn how to [perform a substring search](/spanner/docs/full-text-search/substring-search).\n- Learn how to [paginate search results](/spanner/docs/full-text-search/paginate-search-results).\n- Learn how to [search multiple columns](/spanner/docs/full-text-search/search-multiple-columns)."]]