Compare phrases in PostgreSQL?
ts_rank() is not meant to check for complete equality. It's a simple ranking function that basically just counts the number of matches in a document. The manual:


  Ranks vectors based on the frequency of their matching lexemes.


Consider:

select ts_rank(to_tsvector('eat apple'), phraseto_tsquery('eating apples'))
     , ts_rank(to_tsvector('xxx eat apple yyy'), phraseto_tsquery('eating apples'))
     , ts_rank(to_tsvector('eat apple eat apple'), phraseto_tsquery('eating apples'))
     , ts_rank(to_tsvector('eat apple eat apple eat apple'), phraseto_tsquery('eating apples'))
     , ts_rank(to_tsvector('eat apple eat apple eat apple eat apple eat apple eat apple eat apple eat apple eat apple'), phraseto_tsquery('eating apples'));


The rank is highest for the last expression just because there are many matches. The first two share the same rank.


  Is there any other type of queries to check that "eat apple" completely matches "eating apples"?


You could compare two tsvecor values for equality:

SELECT to_tsvector('eat apple') = to_tsvector('eating apples');


To be sure (and not depend on current locale settings), spell out the text search configuration:

SELECT to_tsvector('english', 'eat apple') = to_tsvector('english', 'eating apples')


Returns true for an exact match.
Not supported by a text search indexes, though, which only support the operators @@, @@@, &lt;@, and @&gt;. You could combine both. Like:

SELECT * FROM tbl
WHERE  to_tsvector(text_field) @@ phraseto_tsquery('eating apples')  -- with index support
ORDER  BY to_tsvector(text_field) &lt;&gt; to_tsvector('eating apples')  -- exact match first
        , ts_rank(to_tsvector(text_field), phraseto_tsquery('eating apples')) DESC


Sorts exact matches first because FALSE sorts before TRUE.