1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Phrase full text search.

Patch introduces new text search operator (<-> or <DISTANCE>) into tsquery.
On-disk and binary in/out format of tsquery are backward compatible.
It has two side effect:
- change order for tsquery, so, users, who has a btree index over tsquery,
  should reindex it
- less number of parenthesis in tsquery output, and tsquery becomes more
  readable

Authors: Teodor Sigaev, Oleg Bartunov, Dmitry Ivanov
Reviewers: Alexander Korotkov, Artur Zakirov
This commit is contained in:
Teodor Sigaev
2016-04-07 18:44:18 +03:00
parent 015e88942a
commit bb140506df
30 changed files with 2542 additions and 450 deletions

View File

@ -434,9 +434,9 @@ SELECT to_tsvector('ispell_tst', 'Booking the skies after rebookings for footbal
(1 row)
SELECT to_tsquery('ispell_tst', 'footballklubber');
to_tsquery
------------------------------------------------------------------------------
( 'footballklubber' | 'foot' & 'ball' & 'klubber' ) | 'football' & 'klubber'
to_tsquery
--------------------------------------------------------------------------
'footballklubber' | 'foot' & 'ball' & 'klubber' | 'football' & 'klubber'
(1 row)
SELECT to_tsquery('ispell_tst', 'footballyklubber:b & rebookings:A & sky');
@ -458,9 +458,9 @@ SELECT to_tsvector('hunspell_tst', 'Booking the skies after rebookings for footb
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballklubber');
to_tsquery
------------------------------------------------------------------------------
( 'footballklubber' | 'foot' & 'ball' & 'klubber' ) | 'football' & 'klubber'
to_tsquery
--------------------------------------------------------------------------
'footballklubber' | 'foot' & 'ball' & 'klubber' | 'football' & 'klubber'
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballyklubber:b & rebookings:A & sky');
@ -469,6 +469,18 @@ SELECT to_tsquery('hunspell_tst', 'footballyklubber:b & rebookings:A & sky');
'foot':B & 'ball':B & 'klubber':B & ( 'booking':A | 'book':A ) & 'sky'
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballyklubber:b <-> sky');
to_tsquery
-----------------------------------------------------------------------------
( 'foot':B <-> 'sky' ) & ( 'ball':B <-> 'sky' ) & ( 'klubber':B <-> 'sky' )
(1 row)
SELECT phraseto_tsquery('hunspell_tst', 'footballyklubber sky');
phraseto_tsquery
-----------------------------------------------------------------------
( 'foot' <-> 'sky' ) & ( 'ball' <-> 'sky' ) & ( 'klubber' <-> 'sky' )
(1 row)
-- Test ispell dictionary with hunspell affix with FLAG long in configuration
ALTER TEXT SEARCH CONFIGURATION hunspell_tst ALTER MAPPING
REPLACE hunspell WITH hunspell_long;
@ -479,9 +491,9 @@ SELECT to_tsvector('hunspell_tst', 'Booking the skies after rebookings for footb
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballklubber');
to_tsquery
------------------------------------------------------------------------------
( 'footballklubber' | 'foot' & 'ball' & 'klubber' ) | 'football' & 'klubber'
to_tsquery
--------------------------------------------------------------------------
'footballklubber' | 'foot' & 'ball' & 'klubber' | 'football' & 'klubber'
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballyklubber:b & rebookings:A & sky');
@ -500,9 +512,9 @@ SELECT to_tsvector('hunspell_tst', 'Booking the skies after rebookings for footb
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballklubber');
to_tsquery
------------------------------------------------------------------------------
( 'footballklubber' | 'foot' & 'ball' & 'klubber' ) | 'football' & 'klubber'
to_tsquery
--------------------------------------------------------------------------
'footballklubber' | 'foot' & 'ball' & 'klubber' | 'football' & 'klubber'
(1 row)
SELECT to_tsquery('hunspell_tst', 'footballyklubber:b & rebookings:A & sky');

View File

@ -554,6 +554,235 @@ SELECT plainto_tsquery('english', 'foo bar') && 'asd | fg';
'foo' & 'bar' & ( 'asd' | 'fg' )
(1 row)
-- Check stop word deletion, a and s are stop-words
SELECT to_tsquery('english', '(1 <-> 2) <-> a');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '(1 <-> a) <-> 2');
to_tsquery
-------------
'1' <2> '2'
(1 row)
SELECT to_tsquery('english', '(a <-> 1) <-> 2');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', 'a <-> (1 <-> 2)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '1 <-> (a <-> 2)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '1 <-> (2 <-> a)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '(1 <-> 2) <3> a');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '(1 <-> a) <3> 2');
to_tsquery
-------------
'1' <4> '2'
(1 row)
SELECT to_tsquery('english', '(a <-> 1) <3> 2');
to_tsquery
-------------
'1' <3> '2'
(1 row)
SELECT to_tsquery('english', 'a <3> (1 <-> 2)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '1 <3> (a <-> 2)');
to_tsquery
-------------
'1' <3> '2'
(1 row)
SELECT to_tsquery('english', '1 <3> (2 <-> a)');
to_tsquery
-------------
'1' <3> '2'
(1 row)
SELECT to_tsquery('english', '(1 <3> 2) <-> a');
to_tsquery
-------------
'1' <3> '2'
(1 row)
SELECT to_tsquery('english', '(1 <3> a) <-> 2');
to_tsquery
-------------
'1' <4> '2'
(1 row)
SELECT to_tsquery('english', '(a <3> 1) <-> 2');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', 'a <-> (1 <3> 2)');
to_tsquery
-------------
'1' <3> '2'
(1 row)
SELECT to_tsquery('english', '1 <-> (a <3> 2)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '1 <-> (2 <3> a)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '((a <-> 1) <-> 2) <-> s');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '(2 <-> (a <-> 1)) <-> s');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', '((1 <-> a) <-> 2) <-> s');
to_tsquery
-------------
'1' <2> '2'
(1 row)
SELECT to_tsquery('english', '(2 <-> (1 <-> a)) <-> s');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', 's <-> ((a <-> 1) <-> 2)');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', 's <-> (2 <-> (a <-> 1))');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', 's <-> ((1 <-> a) <-> 2)');
to_tsquery
-------------
'1' <2> '2'
(1 row)
SELECT to_tsquery('english', 's <-> (2 <-> (1 <-> a))');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', '((a <-> 1) <-> s) <-> 2');
to_tsquery
-------------
'1' <2> '2'
(1 row)
SELECT to_tsquery('english', '(s <-> (a <-> 1)) <-> 2');
to_tsquery
-------------
'1' <-> '2'
(1 row)
SELECT to_tsquery('english', '((1 <-> a) <-> s) <-> 2');
to_tsquery
-------------
'1' <3> '2'
(1 row)
SELECT to_tsquery('english', '(s <-> (1 <-> a)) <-> 2');
to_tsquery
-------------
'1' <2> '2'
(1 row)
SELECT to_tsquery('english', '2 <-> ((a <-> 1) <-> s)');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', '2 <-> (s <-> (a <-> 1))');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', '2 <-> ((1 <-> a) <-> s)');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('english', '2 <-> (s <-> (1 <-> a))');
to_tsquery
-------------
'2' <-> '1'
(1 row)
SELECT to_tsquery('foo <-> (a <-> (the <-> bar))');
to_tsquery
-----------------
'foo' <-> 'bar'
(1 row)
SELECT to_tsquery('((foo <-> a) <-> the) <-> bar');
to_tsquery
-----------------
'foo' <3> 'bar'
(1 row)
SELECT to_tsquery('foo <-> a <-> the <-> bar');
to_tsquery
-----------------
'foo' <3> 'bar'
(1 row)
SELECT phraseto_tsquery('PostgreSQL can be extended by the user in many ways');
phraseto_tsquery
-----------------------------------------------------------------------
( ( ( 'postgresql' <3> 'extend' ) <3> 'user' ) <2> 'mani' ) <-> 'way'
(1 row)
SELECT ts_rank_cd(to_tsvector('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
@ -602,6 +831,22 @@ S. T. Coleridge (1772-1834)
0.1
(1 row)
SELECT ts_rank_cd(to_tsvector('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
As idle as a painted Ship
Upon a painted Ocean.
Water, water, every where
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink.
S. T. Coleridge (1772-1834)
'), to_tsquery('english', 'painted <-> Ship'));
ts_rank_cd
------------
0.1
(1 row)
SELECT ts_rank_cd(strip(to_tsvector('both stripped')),
to_tsquery('both & stripped'));
ts_rank_cd
@ -674,6 +919,44 @@ S. T. Coleridge (1772-1834)
Water, water, every where
(1 row)
SELECT ts_headline('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
As idle as a painted Ship
Upon a painted Ocean.
Water, water, every where
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink.
S. T. Coleridge (1772-1834)
', phraseto_tsquery('english', 'painted Ocean'));
ts_headline
----------------------------------
<b>painted</b> <b>Ocean</b>. +
Water, water, every where +
And all the boards did shrink;+
Water, water, every
(1 row)
SELECT ts_headline('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
As idle as a painted Ship
Upon a painted Ocean.
Water, water, every where
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink.
S. T. Coleridge (1772-1834)
', phraseto_tsquery('english', 'idle as a painted Ship'));
ts_headline
---------------------------------------------
<b>idle</b> as a <b>painted</b> <b>Ship</b>+
Upon a <b>painted</b> Ocean. +
Water, water, every where +
And all the boards
(1 row)
SELECT ts_headline('english', '
<html>
<!-- some comment -->
@ -703,6 +986,24 @@ to_tsquery('english', 'sea&foo'), 'HighlightAll=true');
</html>
(1 row)
SELECT ts_headline('simple', '1 2 3 1 3'::text, '1 <-> 3', 'MaxWords=2, MinWords=1');
ts_headline
-------------------
<b>1</b> <b>3</b>
(1 row)
SELECT ts_headline('simple', '1 2 3 1 3'::text, '1 & 3', 'MaxWords=4, MinWords=1');
ts_headline
------------------------------
<b>1</b> 2 <b>3</b> <b>1</b>
(1 row)
SELECT ts_headline('simple', '1 2 3 1 3'::text, '1 <-> 3', 'MaxWords=4, MinWords=1');
ts_headline
-------------------
<b>1</b> <b>3</b>
(1 row)
--Check if headline fragments work
SELECT ts_headline('english', '
Day after day, day after day,
@ -805,13 +1106,13 @@ UPDATE test_tsquery SET sample = to_tsquery('english', txtsample::text);
SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york';
count
-------
1
2
(1 row)
SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new & york';
count
-------
2
3
(1 row)
SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york';
@ -823,13 +1124,13 @@ SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york';
SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new & york';
count
-------
3
4
(1 row)
SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york';
count
-------
2
3
(1 row)
CREATE UNIQUE INDEX bt_tsq ON test_tsquery (keyword);
@ -837,13 +1138,13 @@ SET enable_seqscan=OFF;
SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york';
count
-------
1
2
(1 row)
SELECT COUNT(*) FROM test_tsquery WHERE keyword <= 'new & york';
count
-------
2
3
(1 row)
SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york';
@ -855,20 +1156,20 @@ SELECT COUNT(*) FROM test_tsquery WHERE keyword = 'new & york';
SELECT COUNT(*) FROM test_tsquery WHERE keyword >= 'new & york';
count
-------
3
4
(1 row)
SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york';
count
-------
2
3
(1 row)
RESET enable_seqscan;
SELECT ts_rewrite('foo & bar & qq & new & york', 'new & york'::tsquery, 'big & apple | nyc | new & york & city');
ts_rewrite
----------------------------------------------------------------------------------
'foo' & 'bar' & 'qq' & ( 'city' & 'new' & 'york' | ( 'nyc' | 'big' & 'apple' ) )
ts_rewrite
------------------------------------------------------------------------------
'foo' & 'bar' & 'qq' & ( 'nyc' | 'big' & 'apple' | 'city' & 'new' & 'york' )
(1 row)
SELECT ts_rewrite('moscow', 'SELECT keyword, sample FROM test_tsquery'::text );
@ -884,9 +1185,9 @@ SELECT ts_rewrite('moscow & hotel', 'SELECT keyword, sample FROM test_tsquery'::
(1 row)
SELECT ts_rewrite('bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery'::text );
ts_rewrite
-------------------------------------------------------------------------------------
'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) )
ts_rewrite
---------------------------------------------------------------------------------
( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' )
(1 row)
SELECT ts_rewrite( 'moscow', 'SELECT keyword, sample FROM test_tsquery');
@ -902,9 +1203,33 @@ SELECT ts_rewrite( 'moscow & hotel', 'SELECT keyword, sample FROM test_tsquery')
(1 row)
SELECT ts_rewrite( 'bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery');
ts_rewrite
-------------------------------------------------------------------------------------
'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) )
ts_rewrite
---------------------------------------------------------------------------------
( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' )
(1 row)
SELECT ts_rewrite('1 & (2 <-> 3)', 'SELECT keyword, sample FROM test_tsquery'::text );
ts_rewrite
-------------
'2' <-> '4'
(1 row)
SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::text );
ts_rewrite
-----------------------
'1' & ( '2' <2> '3' )
(1 row)
SELECT ts_rewrite('5 <-> (1 & (2 <-> 3))', 'SELECT keyword, sample FROM test_tsquery'::text );
ts_rewrite
-----------------------------------------------
( '5' <-> '1' ) & ( '5' <-> ( '2' <-> '3' ) )
(1 row)
SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::text );
ts_rewrite
---------------------------
'5' <-> '7' | '5' <-> '8'
(1 row)
SELECT keyword FROM test_tsquery WHERE keyword @> 'new';
@ -943,9 +1268,9 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t
(1 row)
SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query;
ts_rewrite
-------------------------------------------------------------------------------------
'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) )
ts_rewrite
---------------------------------------------------------------------------------
( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' )
(1 row)
SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query;
@ -961,9 +1286,9 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t
(1 row)
SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query;
ts_rewrite
-------------------------------------------------------------------------------------
'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) )
ts_rewrite
---------------------------------------------------------------------------------
( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' )
(1 row)
CREATE INDEX qq ON test_tsquery USING gist (keyword tsquery_ops);
@ -1004,9 +1329,9 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t
(1 row)
SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query;
ts_rewrite
-------------------------------------------------------------------------------------
'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) )
ts_rewrite
---------------------------------------------------------------------------------
( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' )
(1 row)
SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'moscow') AS query;
@ -1022,9 +1347,9 @@ SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_t
(1 row)
SELECT ts_rewrite( query, 'SELECT keyword, sample FROM test_tsquery' ) FROM to_tsquery('english', 'bar & new & qq & foo & york') AS query;
ts_rewrite
-------------------------------------------------------------------------------------
'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) )
ts_rewrite
---------------------------------------------------------------------------------
( 'nyc' | 'big' & 'appl' | 'new' & 'york' ) & 'citi' & 'foo' & ( 'bar' | 'qq' )
(1 row)
RESET enable_seqscan;
@ -1132,3 +1457,15 @@ select * from pendtest where 'ipi:*'::tsquery @@ ts;
----
(0 rows)
--check OP_PHRASE on index
create temp table phrase_index_test(fts tsvector);
insert into phrase_index_test values('A fat cat has just eaten a rat.');
create index phrase_index_test_idx on phrase_index_test using gin(fts);
set enable_seqscan = off;
select * from phrase_index_test where fts @@ phraseto_tsquery('fat cat');
fts
-------------------------------------------------
'A' 'a' 'cat' 'eaten' 'fat' 'has' 'just' 'rat.'
(1 row)
set enable_seqscan = on;

View File

@ -277,15 +277,15 @@ SELECT '(!1|2)&3'::tsquery;
(1 row)
SELECT '1|(2|(4|(5|6)))'::tsquery;
tsquery
-----------------------------------------
'1' | ( '2' | ( '4' | ( '5' | '6' ) ) )
tsquery
-----------------------------
'1' | '2' | '4' | '5' | '6'
(1 row)
SELECT '1|2|4|5|6'::tsquery;
tsquery
-----------------------------------------
( ( ( '1' | '2' ) | '4' ) | '5' ) | '6'
tsquery
-----------------------------
'1' | '2' | '4' | '5' | '6'
(1 row)
SELECT '1&(2&(4&(5&6)))'::tsquery;
@ -325,11 +325,139 @@ SELECT $$'\\as'$$::tsquery;
(1 row)
SELECT 'a:* & nbb:*ac | doo:a* | goo'::tsquery;
tsquery
------------------------------------------
( 'a':* & 'nbb':*AC | 'doo':*A ) | 'goo'
tsquery
--------------------------------------
'a':* & 'nbb':*AC | 'doo':*A | 'goo'
(1 row)
-- phrase transformation
SELECT 'a <-> (b|c)'::tsquery;
tsquery
---------------------------
'a' <-> 'b' | 'a' <-> 'c'
(1 row)
SELECT '(a|b) <-> c'::tsquery;
tsquery
---------------------------
'a' <-> 'c' | 'b' <-> 'c'
(1 row)
SELECT '(a|b) <-> (d|c)'::tsquery;
tsquery
-------------------------------------------------------
'a' <-> 'd' | 'b' <-> 'd' | 'a' <-> 'c' | 'b' <-> 'c'
(1 row)
SELECT 'a <-> (b&c)'::tsquery;
tsquery
-----------------------------------
( 'a' <-> 'b' ) & ( 'a' <-> 'c' )
(1 row)
SELECT '(a&b) <-> c'::tsquery;
tsquery
-----------------------------------
( 'a' <-> 'c' ) & ( 'b' <-> 'c' )
(1 row)
SELECT '(a&b) <-> (d&c)'::tsquery;
tsquery
-----------------------------------------------------------------------
( 'a' <-> 'd' ) & ( 'b' <-> 'd' ) & ( 'a' <-> 'c' ) & ( 'b' <-> 'c' )
(1 row)
SELECT 'a <-> !b'::tsquery;
tsquery
------------------------
'a' & !( 'a' <-> 'b' )
(1 row)
SELECT '!a <-> b'::tsquery;
tsquery
------------------------
!( 'a' <-> 'b' ) & 'b'
(1 row)
SELECT '!a <-> !b'::tsquery;
tsquery
------------------------------------
!'a' & !( !( 'a' <-> 'b' ) & 'b' )
(1 row)
SELECT 'a <-> !(b&c)'::tsquery;
tsquery
----------------------------------------------
'a' & !( ( 'a' <-> 'b' ) & ( 'a' <-> 'c' ) )
(1 row)
SELECT 'a <-> !(b|c)'::tsquery;
tsquery
--------------------------------------
'a' & !( 'a' <-> 'b' | 'a' <-> 'c' )
(1 row)
SELECT '!(a&b) <-> c'::tsquery;
tsquery
----------------------------------------------
!( ( 'a' <-> 'c' ) & ( 'b' <-> 'c' ) ) & 'c'
(1 row)
SELECT '!(a|b) <-> c'::tsquery;
tsquery
--------------------------------------
!( 'a' <-> 'c' | 'b' <-> 'c' ) & 'c'
(1 row)
SELECT '(!a|b) <-> c'::tsquery;
tsquery
--------------------------------------
!( 'a' <-> 'c' ) & 'c' | 'b' <-> 'c'
(1 row)
SELECT '(!a&b) <-> c'::tsquery;
tsquery
------------------------------------------
!( 'a' <-> 'c' ) & 'c' & ( 'b' <-> 'c' )
(1 row)
SELECT 'c <-> (!a|b)'::tsquery;
tsquery
--------------------------------------
'c' & !( 'c' <-> 'a' ) | 'c' <-> 'b'
(1 row)
SELECT 'c <-> (!a&b)'::tsquery;
tsquery
------------------------------------------
'c' & !( 'c' <-> 'a' ) & ( 'c' <-> 'b' )
(1 row)
SELECT '(a|b) <-> !c'::tsquery;
tsquery
------------------------------------------------
( 'a' | 'b' ) & !( 'a' <-> 'c' | 'b' <-> 'c' )
(1 row)
SELECT '(a&b) <-> !c'::tsquery;
tsquery
----------------------------------------------------
'a' & 'b' & !( ( 'a' <-> 'c' ) & ( 'b' <-> 'c' ) )
(1 row)
SELECT '!c <-> (a|b)'::tsquery;
tsquery
-------------------------------------------------
!( 'c' <-> 'a' ) & 'a' | !( 'c' <-> 'b' ) & 'b'
(1 row)
SELECT '!c <-> (a&b)'::tsquery;
tsquery
-------------------------------------------------
!( 'c' <-> 'a' ) & 'a' & !( 'c' <-> 'b' ) & 'b'
(1 row)
--comparisons
SELECT 'a' < 'b & c'::tsquery as "true";
true
------
@ -342,10 +470,10 @@ SELECT 'a' > 'b & c'::tsquery as "false";
f
(1 row)
SELECT 'a | f' < 'b & c'::tsquery as "true";
true
------
t
SELECT 'a | f' < 'b & c'::tsquery as "false";
false
-------
f
(1 row)
SELECT 'a | ff' < 'b & c'::tsquery as "false";
@ -360,6 +488,7 @@ SELECT 'a | f | g' < 'b & c'::tsquery as "false";
f
(1 row)
--concatenation
SELECT numnode( 'new'::tsquery );
numnode
---------
@ -402,6 +531,36 @@ SELECT 'foo & bar'::tsquery && 'asd | fg';
'foo' & 'bar' & ( 'asd' | 'fg' )
(1 row)
SELECT 'a' <-> 'b & d'::tsquery;
?column?
-----------------------------------
( 'a' <-> 'b' ) & ( 'a' <-> 'd' )
(1 row)
SELECT 'a & g' <-> 'b & d'::tsquery;
?column?
-----------------------------------------------------------------------
( 'a' <-> 'b' ) & ( 'g' <-> 'b' ) & ( 'a' <-> 'd' ) & ( 'g' <-> 'd' )
(1 row)
SELECT 'a & g' <-> 'b | d'::tsquery;
?column?
-----------------------------------------------------------------------
( 'a' <-> 'b' ) & ( 'g' <-> 'b' ) | ( 'a' <-> 'd' ) & ( 'g' <-> 'd' )
(1 row)
SELECT 'a & g' <-> 'b <-> d'::tsquery;
?column?
-----------------------------------------------------------
( 'a' <-> ( 'b' <-> 'd' ) ) & ( 'g' <-> ( 'b' <-> 'd' ) )
(1 row)
SELECT tsquery_phrase('a <3> g', 'b & d', 10);
tsquery_phrase
-------------------------------------------------------------
( ( 'a' <3> 'g' ) <10> 'b' ) & ( ( 'a' <3> 'g' ) <10> 'd' )
(1 row)
-- tsvector-tsquery operations
SELECT 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca' as "true";
true
@ -499,6 +658,80 @@ SELECT 'supeznova supernova'::tsvector @@ 'super:*'::tsquery AS "true";
t
(1 row)
--phrase search
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <-> 2' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <2> 2' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <-> 3' AS "false";
false
-------
f
(1 row)
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <2> 3' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 11 3') @@ '1 <-> 3' AS "false";
false
-------
f
(1 row)
SELECT to_tsvector('simple', '1 2 11 3') @@ '1:* <-> 3' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> (2 <-> 3)' AS "false";
false
-------
f
(1 row)
SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <2> (2 <-> 3)' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true";
true
------
t
(1 row)
SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true";
true
------
t
(1 row)
--ranking
SELECT ts_rank(' a:1 s:2C d g'::tsvector, 'a | s');
ts_rank
-----------
@ -613,6 +846,120 @@ SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a & s');
0.1
(1 row)
SELECT ts_rank_cd(' a:1 s:2A d g'::tsvector, 'a <-> s');
ts_rank_cd
------------
0.181818
(1 row)
SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a <-> s');
ts_rank_cd
------------
0.133333
(1 row)
SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a <-> s');
ts_rank_cd
------------
0.1
(1 row)
SELECT ts_rank_cd(' a:1 s:2 d:2A g'::tsvector, 'a <-> s');
ts_rank_cd
------------
0.1
(1 row)
SELECT ts_rank_cd(' a:1 s:2,3A d:2A g'::tsvector, 'a <2> s:A');
ts_rank_cd
------------
0.0909091
(1 row)
SELECT ts_rank_cd(' a:1 b:2 s:3A d:2A g'::tsvector, 'a <2> s:A');
ts_rank_cd
------------
0.0909091
(1 row)
SELECT ts_rank_cd(' a:1 sa:2D sb:2A g'::tsvector, 'a <-> s:*');
ts_rank_cd
------------
0.1
(1 row)
SELECT ts_rank_cd(' a:1 sa:2A sb:2D g'::tsvector, 'a <-> s:*');
ts_rank_cd
------------
0.1
(1 row)
SELECT ts_rank_cd(' a:1 sa:2A sb:2D g'::tsvector, 'a <-> s:* <-> sa:A');
ts_rank_cd
------------
0.0714286
(1 row)
SELECT ts_rank_cd(' a:1 sa:2A sb:2D g'::tsvector, 'a <-> s:* <-> sa:B');
ts_rank_cd
------------
0
(1 row)
SELECT 'a:1 b:2'::tsvector @@ 'a <-> b'::tsquery AS "true";
true
------
t
(1 row)
SELECT 'a:1 b:2'::tsvector @@ 'a <0> b'::tsquery AS "false";
false
-------
f
(1 row)
SELECT 'a:1 b:2'::tsvector @@ 'a <1> b'::tsquery AS "true";
true
------
t
(1 row)
SELECT 'a:1 b:2'::tsvector @@ 'a <2> b'::tsquery AS "true";
true
------
t
(1 row)
SELECT 'a:1 b:3'::tsvector @@ 'a <-> b'::tsquery AS "false";
false
-------
f
(1 row)
SELECT 'a:1 b:3'::tsvector @@ 'a <0> b'::tsquery AS "false";
false
-------
f
(1 row)
SELECT 'a:1 b:3'::tsvector @@ 'a <1> b'::tsquery AS "false";
false
-------
f
(1 row)
SELECT 'a:1 b:3'::tsvector @@ 'a <2> b'::tsquery AS "true";
true
------
t
(1 row)
SELECT 'a:1 b:3'::tsvector @@ 'a <3> b'::tsquery AS "true";
true
------
t
(1 row)
-- tsvector editing operations
SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
strip

View File

@ -142,6 +142,9 @@ SELECT to_tsvector('hunspell_tst', 'Booking the skies after rebookings for footb
SELECT to_tsquery('hunspell_tst', 'footballklubber');
SELECT to_tsquery('hunspell_tst', 'footballyklubber:b & rebookings:A & sky');
SELECT to_tsquery('hunspell_tst', 'footballyklubber:b <-> sky');
SELECT phraseto_tsquery('hunspell_tst', 'footballyklubber sky');
-- Test ispell dictionary with hunspell affix with FLAG long in configuration
ALTER TEXT SEARCH CONFIGURATION hunspell_tst ALTER MAPPING
REPLACE hunspell WITH hunspell_long;

View File

@ -129,6 +129,52 @@ SELECT plainto_tsquery('english', 'foo bar') || plainto_tsquery('english', 'asd
SELECT plainto_tsquery('english', 'foo bar') || !!plainto_tsquery('english', 'asd fg');
SELECT plainto_tsquery('english', 'foo bar') && 'asd | fg';
-- Check stop word deletion, a and s are stop-words
SELECT to_tsquery('english', '(1 <-> 2) <-> a');
SELECT to_tsquery('english', '(1 <-> a) <-> 2');
SELECT to_tsquery('english', '(a <-> 1) <-> 2');
SELECT to_tsquery('english', 'a <-> (1 <-> 2)');
SELECT to_tsquery('english', '1 <-> (a <-> 2)');
SELECT to_tsquery('english', '1 <-> (2 <-> a)');
SELECT to_tsquery('english', '(1 <-> 2) <3> a');
SELECT to_tsquery('english', '(1 <-> a) <3> 2');
SELECT to_tsquery('english', '(a <-> 1) <3> 2');
SELECT to_tsquery('english', 'a <3> (1 <-> 2)');
SELECT to_tsquery('english', '1 <3> (a <-> 2)');
SELECT to_tsquery('english', '1 <3> (2 <-> a)');
SELECT to_tsquery('english', '(1 <3> 2) <-> a');
SELECT to_tsquery('english', '(1 <3> a) <-> 2');
SELECT to_tsquery('english', '(a <3> 1) <-> 2');
SELECT to_tsquery('english', 'a <-> (1 <3> 2)');
SELECT to_tsquery('english', '1 <-> (a <3> 2)');
SELECT to_tsquery('english', '1 <-> (2 <3> a)');
SELECT to_tsquery('english', '((a <-> 1) <-> 2) <-> s');
SELECT to_tsquery('english', '(2 <-> (a <-> 1)) <-> s');
SELECT to_tsquery('english', '((1 <-> a) <-> 2) <-> s');
SELECT to_tsquery('english', '(2 <-> (1 <-> a)) <-> s');
SELECT to_tsquery('english', 's <-> ((a <-> 1) <-> 2)');
SELECT to_tsquery('english', 's <-> (2 <-> (a <-> 1))');
SELECT to_tsquery('english', 's <-> ((1 <-> a) <-> 2)');
SELECT to_tsquery('english', 's <-> (2 <-> (1 <-> a))');
SELECT to_tsquery('english', '((a <-> 1) <-> s) <-> 2');
SELECT to_tsquery('english', '(s <-> (a <-> 1)) <-> 2');
SELECT to_tsquery('english', '((1 <-> a) <-> s) <-> 2');
SELECT to_tsquery('english', '(s <-> (1 <-> a)) <-> 2');
SELECT to_tsquery('english', '2 <-> ((a <-> 1) <-> s)');
SELECT to_tsquery('english', '2 <-> (s <-> (a <-> 1))');
SELECT to_tsquery('english', '2 <-> ((1 <-> a) <-> s)');
SELECT to_tsquery('english', '2 <-> (s <-> (1 <-> a))');
SELECT to_tsquery('foo <-> (a <-> (the <-> bar))');
SELECT to_tsquery('((foo <-> a) <-> the) <-> bar');
SELECT to_tsquery('foo <-> a <-> the <-> bar');
SELECT phraseto_tsquery('PostgreSQL can be extended by the user in many ways');
SELECT ts_rank_cd(to_tsvector('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
@ -165,6 +211,18 @@ Water, water, every where,
S. T. Coleridge (1772-1834)
'), to_tsquery('english', 'ocean'));
SELECT ts_rank_cd(to_tsvector('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
As idle as a painted Ship
Upon a painted Ocean.
Water, water, every where
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink.
S. T. Coleridge (1772-1834)
'), to_tsquery('english', 'painted <-> Ship'));
SELECT ts_rank_cd(strip(to_tsvector('both stripped')),
to_tsquery('both & stripped'));
@ -208,6 +266,30 @@ Water, water, every where,
S. T. Coleridge (1772-1834)
', to_tsquery('english', 'ocean'));
SELECT ts_headline('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
As idle as a painted Ship
Upon a painted Ocean.
Water, water, every where
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink.
S. T. Coleridge (1772-1834)
', phraseto_tsquery('english', 'painted Ocean'));
SELECT ts_headline('english', '
Day after day, day after day,
We stuck, nor breath nor motion,
As idle as a painted Ship
Upon a painted Ocean.
Water, water, every where
And all the boards did shrink;
Water, water, every where,
Nor any drop to drink.
S. T. Coleridge (1772-1834)
', phraseto_tsquery('english', 'idle as a painted Ship'));
SELECT ts_headline('english', '
<html>
<!-- some comment -->
@ -222,6 +304,10 @@ ff-bg
</html>',
to_tsquery('english', 'sea&foo'), 'HighlightAll=true');
SELECT ts_headline('simple', '1 2 3 1 3'::text, '1 <-> 3', 'MaxWords=2, MinWords=1');
SELECT ts_headline('simple', '1 2 3 1 3'::text, '1 & 3', 'MaxWords=4, MinWords=1');
SELECT ts_headline('simple', '1 2 3 1 3'::text, '1 <-> 3', 'MaxWords=4, MinWords=1');
--Check if headline fragments work
SELECT ts_headline('english', '
Day after day, day after day,
@ -283,6 +369,8 @@ CREATE TABLE test_tsquery (txtkeyword TEXT, txtsample TEXT);
Moscow moskva | moscow
'Sanct Peter' Peterburg | peter | 'Sanct Peterburg'
'foo bar qq' foo & (bar | qq) & city
1 & (2 <-> 3) 2 <-> 4
5 <-> 6 5 <-> 7
\.
\set ECHO all
@ -320,6 +408,11 @@ SELECT ts_rewrite( 'moscow', 'SELECT keyword, sample FROM test_tsquery');
SELECT ts_rewrite( 'moscow & hotel', 'SELECT keyword, sample FROM test_tsquery');
SELECT ts_rewrite( 'bar & new & qq & foo & york', 'SELECT keyword, sample FROM test_tsquery');
SELECT ts_rewrite('1 & (2 <-> 3)', 'SELECT keyword, sample FROM test_tsquery'::text );
SELECT ts_rewrite('1 & (2 <2> 3)', 'SELECT keyword, sample FROM test_tsquery'::text );
SELECT ts_rewrite('5 <-> (1 & (2 <-> 3))', 'SELECT keyword, sample FROM test_tsquery'::text );
SELECT ts_rewrite('5 <-> (6 | 8)', 'SELECT keyword, sample FROM test_tsquery'::text );
SELECT keyword FROM test_tsquery WHERE keyword @> 'new';
SELECT keyword FROM test_tsquery WHERE keyword @> 'moscow';
@ -386,3 +479,11 @@ select * from pendtest where 'ipsa:*'::tsquery @@ ts;
select * from pendtest where 'ips:*'::tsquery @@ ts;
select * from pendtest where 'ipt:*'::tsquery @@ ts;
select * from pendtest where 'ipi:*'::tsquery @@ ts;
--check OP_PHRASE on index
create temp table phrase_index_test(fts tsvector);
insert into phrase_index_test values('A fat cat has just eaten a rat.');
create index phrase_index_test_idx on phrase_index_test using gin(fts);
set enable_seqscan = off;
select * from phrase_index_test where fts @@ phraseto_tsquery('fat cat');
set enable_seqscan = on;

View File

@ -58,12 +58,42 @@ SELECT E'1&(''2''&('' 4''&(\\|5 | ''6 \\'' !|&'')))'::tsquery;
SELECT $$'\\as'$$::tsquery;
SELECT 'a:* & nbb:*ac | doo:a* | goo'::tsquery;
-- phrase transformation
SELECT 'a <-> (b|c)'::tsquery;
SELECT '(a|b) <-> c'::tsquery;
SELECT '(a|b) <-> (d|c)'::tsquery;
SELECT 'a <-> (b&c)'::tsquery;
SELECT '(a&b) <-> c'::tsquery;
SELECT '(a&b) <-> (d&c)'::tsquery;
SELECT 'a <-> !b'::tsquery;
SELECT '!a <-> b'::tsquery;
SELECT '!a <-> !b'::tsquery;
SELECT 'a <-> !(b&c)'::tsquery;
SELECT 'a <-> !(b|c)'::tsquery;
SELECT '!(a&b) <-> c'::tsquery;
SELECT '!(a|b) <-> c'::tsquery;
SELECT '(!a|b) <-> c'::tsquery;
SELECT '(!a&b) <-> c'::tsquery;
SELECT 'c <-> (!a|b)'::tsquery;
SELECT 'c <-> (!a&b)'::tsquery;
SELECT '(a|b) <-> !c'::tsquery;
SELECT '(a&b) <-> !c'::tsquery;
SELECT '!c <-> (a|b)'::tsquery;
SELECT '!c <-> (a&b)'::tsquery;
--comparisons
SELECT 'a' < 'b & c'::tsquery as "true";
SELECT 'a' > 'b & c'::tsquery as "false";
SELECT 'a | f' < 'b & c'::tsquery as "true";
SELECT 'a | f' < 'b & c'::tsquery as "false";
SELECT 'a | ff' < 'b & c'::tsquery as "false";
SELECT 'a | f | g' < 'b & c'::tsquery as "false";
--concatenation
SELECT numnode( 'new'::tsquery );
SELECT numnode( 'new & york'::tsquery );
SELECT numnode( 'new & york | qwery'::tsquery );
@ -72,6 +102,11 @@ SELECT 'foo & bar'::tsquery && 'asd';
SELECT 'foo & bar'::tsquery || 'asd & fg';
SELECT 'foo & bar'::tsquery || !!'asd & fg'::tsquery;
SELECT 'foo & bar'::tsquery && 'asd | fg';
SELECT 'a' <-> 'b & d'::tsquery;
SELECT 'a & g' <-> 'b & d'::tsquery;
SELECT 'a & g' <-> 'b | d'::tsquery;
SELECT 'a & g' <-> 'b <-> d'::tsquery;
SELECT tsquery_phrase('a <3> g', 'b & d', 10);
-- tsvector-tsquery operations
@ -93,6 +128,23 @@ SELECT 'supernova'::tsvector @@ 'super:*'::tsquery AS "true";
SELECT 'supeanova supernova'::tsvector @@ 'super:*'::tsquery AS "true";
SELECT 'supeznova supernova'::tsvector @@ 'super:*'::tsquery AS "true";
--phrase search
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <-> 2' AS "true";
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <2> 2' AS "true";
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <-> 3' AS "false";
SELECT to_tsvector('simple', '1 2 3 1') @@ '1 <2> 3' AS "true";
SELECT to_tsvector('simple', '1 2 11 3') @@ '1 <-> 3' AS "false";
SELECT to_tsvector('simple', '1 2 11 3') @@ '1:* <-> 3' AS "true";
SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true";
SELECT to_tsvector('simple', '1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true";
SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <-> (2 <-> 3)' AS "false";
SELECT to_tsvector('simple', '1 2 3 4') @@ '1 <2> (2 <-> 3)' AS "true";
SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '(1 <-> 2) <-> 3' AS "true";
SELECT to_tsvector('simple', '1 2 1 2 3 4') @@ '1 <-> 2 <-> 3' AS "true";
--ranking
SELECT ts_rank(' a:1 s:2C d g'::tsvector, 'a | s');
SELECT ts_rank(' a:1 sa:2C d g'::tsvector, 'a | s');
SELECT ts_rank(' a:1 sa:2C d g'::tsvector, 'a | s:*');
@ -114,6 +166,27 @@ SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a & s');
SELECT ts_rank_cd(' a:1 s:2B d g'::tsvector, 'a & s');
SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a & s');
SELECT ts_rank_cd(' a:1 s:2A d g'::tsvector, 'a <-> s');
SELECT ts_rank_cd(' a:1 s:2C d g'::tsvector, 'a <-> s');
SELECT ts_rank_cd(' a:1 s:2 d g'::tsvector, 'a <-> s');
SELECT ts_rank_cd(' a:1 s:2 d:2A g'::tsvector, 'a <-> s');
SELECT ts_rank_cd(' a:1 s:2,3A d:2A g'::tsvector, 'a <2> s:A');
SELECT ts_rank_cd(' a:1 b:2 s:3A d:2A g'::tsvector, 'a <2> s:A');
SELECT ts_rank_cd(' a:1 sa:2D sb:2A g'::tsvector, 'a <-> s:*');
SELECT ts_rank_cd(' a:1 sa:2A sb:2D g'::tsvector, 'a <-> s:*');
SELECT ts_rank_cd(' a:1 sa:2A sb:2D g'::tsvector, 'a <-> s:* <-> sa:A');
SELECT ts_rank_cd(' a:1 sa:2A sb:2D g'::tsvector, 'a <-> s:* <-> sa:B');
SELECT 'a:1 b:2'::tsvector @@ 'a <-> b'::tsquery AS "true";
SELECT 'a:1 b:2'::tsvector @@ 'a <0> b'::tsquery AS "false";
SELECT 'a:1 b:2'::tsvector @@ 'a <1> b'::tsquery AS "true";
SELECT 'a:1 b:2'::tsvector @@ 'a <2> b'::tsquery AS "true";
SELECT 'a:1 b:3'::tsvector @@ 'a <-> b'::tsquery AS "false";
SELECT 'a:1 b:3'::tsvector @@ 'a <0> b'::tsquery AS "false";
SELECT 'a:1 b:3'::tsvector @@ 'a <1> b'::tsquery AS "false";
SELECT 'a:1 b:3'::tsvector @@ 'a <2> b'::tsquery AS "true";
SELECT 'a:1 b:3'::tsvector @@ 'a <3> b'::tsquery AS "true";
-- tsvector editing operations
SELECT strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);