12.3. 細部控制

    PostgreSQLprovides the functionto_tsvectorfor converting a document to thetsvectordata type.

    to_tsvectorparses a textual document into tokens, reduces the tokens to lexemes, and returns atsvectorwhich lists the lexemes together with their positions in the document. The document is processed according to the specified or default text search configuration. Here is a simple example:

    1. SELECT to_tsvector('english', 'a fat cat sat on a mat - it ate a fat rats');
    2. to_tsvector
    3. -----------------------------------------------------
    4. 'ate':9 'cat':3 'fat':2,11 'mat':7 'rat':12 'sat':4

    In the example above we see that the resultingtsvectordoes not contain the wordsa,on, orit, the wordratsbecamerat, and the punctuation sign-was ignored.

    Theto_tsvectorfunction internally calls a parser which breaks the document text into tokens and assigns a type to each token. For each token, a list of dictionaries (Section 12.6) is consulted, where the list can vary depending on the token type. The first dictionary thatrecognizes_the token emits one or more normalized_lexemes_to represent the token. For example,ratsbecameratbecause one of the dictionaries recognized that the wordratsis a plural form ofrat. Some words are recognized as_stop words(), which causes them to be ignored since they occur too frequently to be useful in searching. In our example these area,on, andit. If no dictionary in the list recognizes the token then it is also ignored. In this example that happened to the punctuation sign-because there are in fact no dictionaries assigned for its token type (Space symbols), meaning space tokens will never be indexed. The choices of parser, dictionaries and which types of tokens to index are determined by the selected text search configuration (Section 12.7). It is possible to have many different configurations in the same database, and predefined configurations are available for various languages. In our example we used the default configurationenglishfor the English language.

    The functionsetweightcan be used to label the entries of atsvectorwith a givenweight, where a weight is one of the lettersA,B,C, orD. This is typically used to mark entries coming from different parts of a document, such as title versus body. Later, this information can be used for ranking of search results.

    Becauseto_tsvector(NULL) will returnNULL, it is recommended to usecoalescewhenever a field might be null. Here is the recommended method for creating atsvectorfrom a structured document:

    1. UPDATE tt SET ti =
    2. setweight(to_tsvector(coalesce(title,'')), 'A') ||
    3. setweight(to_tsvector(coalesce(keyword,'')), 'B') ||
    4. setweight(to_tsvector(coalesce(abstract,'')), 'C') ||
    5. setweight(to_tsvector(coalesce(body,'')), 'D');

    Here we have usedsetweightto label the source of each lexeme in the finishedtsvector, and then merged the labeledtsvectorvalues using thetsvectorconcatenation operator||. (gives details about these operations.)

    PostgreSQLprovides the functionsto_tsquery,plainto_tsquery, andphraseto_tsqueryfor converting a query to thetsquerydata type.to_tsqueryoffers access to more features than eitherplainto_tsqueryorphraseto_tsquery, but it is less forgiving about its input.

    1. to_tsquery([
    2. config
    3. regconfig
    4. ,
    5. ]
    6. querytext
    7. text
    8. ) returns
    9. tsquery

    to_tsquerycreates atsqueryvalue fromquerytext, which must consist of single tokens separated by thetsqueryoperators&(AND),|(OR),!(NOT), and<->(FOLLOWED BY), possibly grouped using parentheses. In other words, the input toto_tsquerymust already follow the general rules fortsqueryinput, as described inSection 8.11.2. The difference is that while basictsqueryinput takes the tokens at face value,to_tsquerynormalizes each token into a lexeme using the specified or default configuration, and discards any tokens that are stop words according to the configuration. For example:

    1. SELECT to_tsquery('english', 'The
    2. &
    3. Fat
    4. &
    5. Rats');
    6. to_tsquery
    7. ---------------
    8. 'fat'
    9. &
    10. 'rat'

    As in basictsqueryinput, weight(s) can be attached to each lexeme to restrict it to match onlytsvectorlexemes of those weight(s). For example:

    1. SELECT to_tsquery('english', 'Fat | Rats:AB');
    2. to_tsquery
    3. ------------------
    4. 'fat' | 'rat':AB

    Also,*can be attached to a lexeme to specify prefix matching:

    1. SELECT to_tsquery('supern:*A
    2. &
    3. star:A*B');
    4. to_tsquery
    5. --------------------------
    6. 'supern':*A
    7. &
    8. 'star':*AB

    Such a lexeme will match any word in atsvectorthat begins with the given string.

    to_tsquerycan also accept single-quoted phrases. This is primarily useful when the configuration includes a thesaurus dictionary that may trigger on such phrases. In the example below, a thesaurus contains the rulesupernovae stars : sn:

    Without quotes,to_tsquerywill generate a syntax error for tokens that are not separated by an AND, OR, or FOLLOWED BY operator.

    1. plainto_tsquery([
    2. config
    3. regconfig
    4. ,
    5. ]
    6. querytext
    7. text
    8. ) returns
    9. tsquery

    plainto_tsquerytransforms the unformatted text_querytext_to atsqueryvalue. The text is parsed and normalized much as forto_tsvector, then the&(AND)tsqueryoperator is inserted between surviving words.

    Example:

    1. SELECT plainto_tsquery('english', 'The Fat Rats');
    2. -----------------
    3. 'fat'
    4. &
    5. 'rat'

    Note thatplainto_tsquerywill not recognizetsqueryoperators, weight labels, or prefix-match labels in its input:

    1. SELECT plainto_tsquery('english', 'The Fat
    2. &
    3. Rats:C');
    4. plainto_tsquery
    5. ---------------------
    6. 'fat'
    7. &
    8. 'rat'
    9. &
    10. 'c'

    Here, all the input punctuation was discarded as being space symbols.

    1. phraseto_tsquery([
    2. config
    3. regconfig
    4. ,
    5. ]
    6. querytext
    7. text
    8. ) returns
    9. tsquery

    phraseto_tsquerybehaves much likeplainto_tsquery, except that it inserts the<->(FOLLOWED BY) operator between surviving words instead of the&(AND) operator. Also, stop words are not simply discarded, but are accounted for by inserting<N>operators rather than<->operators. This function is useful when searching for exact lexeme sequences, since the FOLLOWED BY operators check lexeme order not just the presence of all the lexemes.

    Example:

    1. SELECT phraseto_tsquery('english', 'The Fat Rats');
    2. phraseto_tsquery
    3. ------------------
    4. <
    5. -
    6. >
    7. 'rat'

    Likeplainto_tsquery, thephraseto_tsqueryfunction will not recognizetsqueryoperators, weight labels, or prefix-match labels in its input:

    1. SELECT phraseto_tsquery('english', 'The Fat
    2. &
    3. Rats:C');
    4. phraseto_tsquery
    5. -----------------------------
    6. 'fat'
    7. <
    8. -
    9. >
    10. 'rat'
    11. <
    12. -
    13. >
    14. 'c'

    Ranking attempts to measure how relevant documents are to a particular query, so that when there are many matches the most relevant ones can be shown first.PostgreSQLprovides two predefined ranking functions, which take into account lexical, proximity, and structural information; that is, they consider how often the query terms appear in the document, how close together the terms are in the document, and how important is the part of the document where they occur. However, the concept of relevancy is vague and very application-specific. Different applications might require additional information for ranking, e.g., document modification time. The built-in ranking functions are only examples. You can write your own ranking functions and/or combine their results with additional factors to fit your specific needs.

    The two ranking functions currently available are:

    weights

    float4[]

    ,

    ]

    vector

    tsvector

    ,

    query

    tsquery

    [

    ,

    normalization

    integer

    ]) returns

    float4

    Ranks vectors based on the frequency of their matching lexemes.

    ts_rank_cd([

    weights

    float4[]

    ,

    ]

    vector

    tsvector

    query

    tsquery

    [

    ,

    normalization

    integer

    ]) returns

    float4

    This function computes the_cover density_ranking for the given document vector and query, as described in Clarke, Cormack, and Tudhope’s “Relevance Ranking for One to Three Term Queries” in the journal “Information Processing and Management”, 1999. Cover density is similar tots_rankranking except that the proximity of matching lexemes to each other is taken into consideration.

    This function requires lexeme positional information to perform its calculation. Therefore, it ignores any“stripped”lexemes in thetsvector. If there are no unstripped lexemes in the input, the result will be zero. (Seefor more information about thestripfunction and positional information intsvectors.)

    For both these functions, the optional_weights_argument offers the ability to weigh word instances more or less heavily depending on how they are labeled. The weight arrays specify how heavily to weigh each category of word, in the order:

    If no_weights_are provided, then these defaults are used:

    1. {0.1, 0.2, 0.4, 1.0}

    Typically weights are used to mark words from special areas of the document, like the title or an initial abstract, so they can be treated with more or less importance than words in the document body.

    Since a longer document has a greater chance of containing a query term it is reasonable to take into account document size, e.g., a hundred-word document with five instances of a search word is probably more relevant than a thousand-word document with five instances. Both ranking functions take an integer_normalization_option that specifies whether and how a document’s length should impact its rank. The integer option controls several behaviors, so it is a bit mask: you can specify one or more behaviors using|(for example,2|4).

    • 0 (the default) ignores the document length
    • 1 divides the rank by 1 + the logarithm of the document length
    • 2 divides the rank by the document length
    • 4 divides the rank by the mean harmonic distance between extents (this is implemented only byts_rank_cd)
    • 8 divides the rank by the number of unique words in document
    • 16 divides the rank by 1 + the logarithm of the number of unique words in document
    • 32 divides the rank by itself + 1

    If more than one flag bit is specified, the transformations are applied in the order listed.

    It is important to note that the ranking functions do not use any global information, so it is impossible to produce a fair normalization to 1% or 100% as sometimes desired. Normalization option 32 (rank/(rank+1)) can be applied to scale all ranks into the range zero to one, but of course this is just a cosmetic change; it will not affect the ordering of the search results.

    Here is an example that selects only the ten highest-ranked matches:

    1. SELECT title, ts_rank_cd(textsearch, query) AS rank
    2. FROM apod, to_tsquery('neutrino|(dark
    3. &
    4. matter)') query
    5. WHERE query @@ textsearch
    6. ORDER BY rank DESC
    7. LIMIT 10;
    8. title | rank
    9. -----------------------------------------------+----------
    10. Neutrinos in the Sun | 3.1
    11. The Sudbury Neutrino Detector | 2.4
    12. A MACHO View of Galactic Dark Matter | 2.01317
    13. Hot Gas and Dark Matter | 1.91171
    14. The Virgo Cluster: Hot Plasma and Dark Matter | 1.90953
    15. Rafting for Solar Neutrinos | 1.9
    16. NGC 4650A: Strange Galaxy and Dark Matter | 1.85774
    17. Hot Gas and Dark Matter | 1.6123
    18. Ice Fishing for Cosmic Neutrinos | 1.6
    19. Weak Lensing Distorts the Universe | 0.818218

    This is the same example using normalized ranking:

    1. SELECT title, ts_rank_cd(textsearch, query, 32 /* rank/(rank+1) */ ) AS rank
    2. FROM apod, to_tsquery('neutrino|(dark
    3. &
    4. matter)') query
    5. WHERE query @@ textsearch
    6. ORDER BY rank DESC
    7. LIMIT 10;
    8. title | rank
    9. -----------------------------------------------+-------------------
    10. Neutrinos in the Sun | 0.756097569485493
    11. The Sudbury Neutrino Detector | 0.705882361190954
    12. A MACHO View of Galactic Dark Matter | 0.668123210574724
    13. Hot Gas and Dark Matter | 0.65655958650282
    14. The Virgo Cluster: Hot Plasma and Dark Matter | 0.656301290640973
    15. NGC 4650A: Strange Galaxy and Dark Matter | 0.650072921219637
    16. Hot Gas and Dark Matter | 0.617195790024749
    17. Ice Fishing for Cosmic Neutrinos | 0.615384618911517
    18. Weak Lensing Distorts the Universe | 0.450010798361481

    Ranking can be expensive since it requires consulting thetsvectorof each matching document, which can be I/O bound and therefore slow. Unfortunately, it is almost impossible to avoid since practical queries often result in large numbers of matches.

    To present search results it is ideal to show a part of each document and how it is related to the query. Usually, search engines show fragments of the document with marked search terms.PostgreSQLprovides a functionts_headlinethat implements this functionality.

    1. ts_headline([
    2. config
    3. regconfig
    4. ,
    5. ]
    6. document
    7. text
    8. ,
    9. query
    10. tsquery
    11. [
    12. ,
    13. options
    14. text
    15. ]) returns
    16. text

    ts_headlineaccepts a document along with a query, and returns an excerpt from the document in which terms from the query are highlighted. The configuration to be used to parse the document can be specified byconfig; if_config_is omitted, thedefault_text_search_configconfiguration is used.

    If anoptions_string is specified it must consist of a comma-separated list of one or moreoption=value_pairs. The available options are:

    • StartSel,StopSel: the strings with which to delimit query words appearing in the document, to distinguish them from other excerpted words. You must double-quote these strings if they contain spaces or commas.
    • ShortWord: words of this length or less will be dropped at the start and end of a headline. The default value of three eliminates common English articles.
    • HighlightAll: Boolean flag; iftruethe whole document will be used as the headline, ignoring the preceding three parameters.
    • MaxFragments: maximum number of text excerpts or fragments to display. The default value of zero selects a non-fragment-oriented headline generation method. A value greater than zero selects fragment-based headline generation. This method finds text fragments with as many query words as possible and stretches those fragments around the query words. As a result query words are close to the middle of each fragment and have words on each side. Each fragment will be of at mostMaxWordsand words of lengthShortWordor less are dropped at the start and end of each fragment. If not all query words are found in the document, then a single fragment of the firstMinWordsin the document will be displayed.
    • FragmentDelimiter: When more than one fragment is displayed, the fragments will be separated by this string.

    Any unspecified options receive these defaults:

    1. StartSel=
    2. <
    3. b
    4. >
    5. , StopSel=
    6. <
    7. /b
    8. >
    9. ,
    10. MaxWords=35, MinWords=15, ShortWord=3, HighlightAll=FALSE,
    11. MaxFragments=0, FragmentDelimiter=" ... "
    1. SELECT ts_headline('english',
    2. 'The most common type of search
    3. is to find all documents containing given query terms
    4. and return them in order of their similarity to the
    5. query.',
    6. to_tsquery('query
    7. &
    8. similarity'));
    9. ts_headline
    10. ------------------------------------------------------------
    11. containing given
    12. <
    13. b
    14. >
    15. query
    16. <
    17. /b
    18. >
    19. terms
    20. and return them in order of their
    21. <
    22. b
    23. >
    24. similarity
    25. <
    26. /b
    27. >
    28. to the
    29. <
    30. b
    31. >
    32. query
    33. <
    34. /b
    35. >
    36. .
    37. SELECT ts_headline('english',
    38. 'The most common type of search
    39. is to find all documents containing given query terms
    40. and return them in order of their similarity to the
    41. query.',
    42. to_tsquery('query
    43. &
    44. similarity'),
    45. 'StartSel =
    46. <
    47. , StopSel =
    48. >
    49. ');
    50. ts_headline
    51. -------------------------------------------------------
    52. containing given
    53. <
    54. query
    55. >
    56. terms
    57. and return them in order of their
    58. <
    59. similarity
    60. >
    61. to the
    62. <
    63. query
    64. .

    ts_headlineuses the original document, not atsvectorsummary, so it can be slow and should be used with care.