Some PostgreSQL syntax and features are unsupported. For details, see Unsupported features.
How does full-text search work?
In the PostgreSQL terminology, a document is a natural-language text converted to a data type that is searchable using specially formatted queries. A document is typically stored within a single database row or concatenated from multiple fields. A full-text search has the following advantages over pattern matching withLIKE and ILIKE:
- A full-text search can specify a text search configuration that enables language-specific searches.
- The results of a full-text search can be ranked.
- A full-text search can be accelerated using a full-text index.
LIKEandILIKEare only fast for prefix searches or when indexed with a .
Process a document
To make a document searchable, convert it to the data type. ATSVECTOR value consists of individual lexemes, which are normalized strings used for text matching. Each lexeme also includes a list of integer positions that indicate where the lexeme existed in the original document.
The to_tsvector() converts a string input into a TSVECTOR value:
TSVECTOR consists of the lexemes get, internet, and tree. Normalization removes the following from the input:
- Derivatives of words, which are reduced using a stemming algorithm. In this example, “trees” is normalized to
tree. - Stop words. These are words that are considered not useful for indexing and searching, based on the text search configuration. This example does not specify a configuration, and
englishis used by default. “How”, “do”, “on”, and “the” are identified as stop words. - Punctuation and capitalization.
get is in the fourth position, internet is in the seventh position, and tree is in the third position in the input.
Form a query
A full-text search attempts to match a query to a document. A full-text search query has the data type. LikeTSVECTOR, a TSQUERY value consists of individual lexemes, which are normalized strings used for text matching. Lexemes in a TSQUERY are separated with any combination of & (AND), | (OR), <-> (FOLLOWED BY), or ! (NOT) operators.
-
The
to_tsquery()normalizes aTSQUERYinput. The input must also be formatted as aTSQUERY, or the statement will error. -
The
plainto_tsquery()converts a string input into aTSQUERYvalue, and separates the lexemes with&(AND): -
The
phraseto_tsquery()converts a string input into aTSQUERYvalue, and separates the lexemes with<->(FOLLOWED BY):In the preceding output,<->(equivalent to<1>) indicates thatgetmust followtreein a matchingTSVECTOR.<3>further indicates thatgetandinternetmust be separated by two lexemes in a matchingTSVECTOR. This resulted from converting the stop words “on” and “the” in the input. To match this query, a document must therefore contain phrases such as “get tree” and “get internet”.
@@ comparison operator. For usage examples, see Match queries to documents.
Rank search results
You can rank the results of a full-text search. Thets_rank() outputs a search rank based on the frequency of matching lexemes. In the following example, two lexemes match:
Because a rank must be calculated for each matching document, ranking a full-text search can incur a performance overhead if there are many matching documents.
ts_rank(), see the PostgreSQL documentation.
Comparisons
Full-text searches support the following comparison operator:- matching: . This operator is set between a
TSQUERYandTSVECTOR, and returnstrueif the lexemes match. TheTSQUERYandTSVECTORcan be specified in any order.
Full-text indexes
You can perform full-text searches without a full-text index. However, an index will drastically improve search performance when searching a large number of documents.
TSVECTOR column.
-
Using the PostgreSQL-compatible syntax:
GIN and GiST indexes are implemented identically on CockroachDB.
GIN and GIST are therefore synonymous when defining a full-text index.-
Using
CREATE INVERTED INDEX:
Text search configuration
A text search configuration determines how inputs are parsed intoTSVECTOR and TSQUERY values. This includes a dictionary that is used to identify derivatives of words, as well as stop words to exclude when normalizing documents and queries.
The supported dictionaries are English, Danish, Dutch, Finnish, French, German, Hungarian, Italian, Norwegian, Portuguese, Russian, Spanish, Swedish, and Turkish. An additional simple dictionary does not perform stemming or stopwording when normalizing documents or queries.
You can specify a text search configuration as the first parameter when calling any of the to process a document or form a query. For example:
english and can be changed as follows:
At this time, only the dictionary can be specified in a text search configuration. See Unsupported features.
Examples
Match queries to documents
Use the@@ operator to match a query (TSQUERY) to a searchable document (TSVECTOR). In the following example, because the TSQUERY comprises the lexemes get and internet, which are both contained in the TSVECTOR, the output will be true:
plainto_tsquery() to match text to a searchable document. This search is equivalent to the preceding example:
phraseto_tsquery() to match text phrases to a searchable document. Because phraseto_tsquery() separates the lexemes get and internet with the <-> (FOLLOWED BY) operator, and the document does not contain a phrase like “get internet”, the output will be false:
Create a full-text index with an expression
You can create an on aSTRING column, using to_tsvector() to convert the value to TSVECTOR.
Given the table:
a to TSVECTOR:
When using a in an expression index, you must specify a text search configuration. In the preceding example, the
english configuration is specified.Create a full-text index with a stored computed column
You can create a full-text index on a that has aTSVECTOR data type.
Given the table:
TSVECTOR column that is computed from a using to_tsvector():
When using a in a stored generated column, you must specify a text search configuration. In the preceding example, the
english configuration is specified.TSVECTOR column:
Perform a full-text search with ranked results
-
Create a table with
STRINGcolumns: -
Populate the table with sample values. These are the documents that you will search:
-
You can use
LIKEorILIKEto search for text. However, the results will be unranked: -
Create a full-text index on the concatenation of both table columns, specifying a text search configuration (in this case,
english), as is mandatory when defining an expression index:
Because inverted joins on
TSVECTOR values are not yet supported, this index won’t be used to accelerate the SQL queries in this example. See Unsupported features.-
Search the table for a query (in this case,
tree), and rank the results. In the following statement,to_tsvector()makes the table values searchable,to_tsquery()forms the query, andts_rank()calculates the search rankings:The frequency of thetreelexeme in each row determines the difference in the rankings. -
Search the table for the query
calling, and rank the results:Unlike pattern matching withLIKEandILIKE, a full-text search forcallingproduced matches. This is becauseto_tsvector()andto_tsquery()each normalized derivatives of the word “call” in their respective inputs to the lexemecall, using the defaultenglishtext search configuration. -
Use
plainto_tsquery()to convert text input to a search query: -
Alternatively, use
phraseto_tsquery()to search for matching text phrases (in this example, “joke dad”):
Unsupported features
Some PostgreSQL syntax and features are unsupported. These include, but are not limited to:- Aspects of text search configurations other than the specified dictionary.
websearch_to_tsquery()built-in function.tsquery_phrase()built-in function.ts_rank_cd()built-in function.setweight()built-in function.- Inverted joins on
TSVECTORvalues. tsvector || tsvectorcomparisons.tsquery || tsquerycomparisons.tsquery && tsquerycomparisons.tsquery <-> tsquerycomparisons.!! tsquerycomparisons.tsquery @> tsqueryandtsquery <@ tsquerycomparisons.
See also
- PostgreSQL documentation on Full Text Search

