Learn how ranking works in Vespa by using the open query API of
vespa-documentation-search.
In this article, find a set of queries invoking different rank-profiles, which is the ranking definition.
Ranking is the user-defined computation that scores documents to a query,
here configured in doc.sd,
also see schema documentation.
This schema has a set of (contrived) ranking functions, to help learn Vespa ranking.
Ranking using document features only
Let's start with something simple: Irrespective of the query, score all documents by the number of in-links to it.
That is, for any query, return the documents with most in-links first in the result set (these queries are clickable!):
Count the number of entries in inlinks in the result and compare with relevance - it will be the same.
Observe that the ranking expression does not use any features from the query,
it only uses attribute(inlinks).count,
which is a document feature.
Observing values used in ranking
When developing ranking expressions, it is useful to observe the input values.
Output the input values using summary-features.
In this experiment, we will use another rank function, still counting in-links but scoring older documents lower:
In the query results, here we observe a document with 27 in-links, 9703 seconds old, get at relevance at 20.32
(the age of documents will vary with query time):
Using summary-features makes it easy to validate and develop the ranking expression.
Ranking with query features
Let's assume we want to find similar documents, and we define document similarity as having the same number of words.
From most perspectives, this is a poor similarity function, better functions are described later.
The documents have a term_count field -
so let's add an input.query() for term count:
The key learning here is how to transfer ranking features in the query, using input.query().
Use different names for more query features.
Ranking with a query tensor
Another similarity function can be overlap in in-links.
We will map the inlinks weightedset into a
tensor,
query with a tensor of same type and create a scalar using a tensor product as the rank score.
We use a mapped query tensor,
where the document name is the address in the tensor, using a value of 1 for each in-link:
Here, the tensors have one dimension, so they are vectors -
the sum of the tensor product is hence the doc product.
As all values are 1, all products are 1 and the sum is 2:
document
query
value
/en/jdisc/container-components.html
0
/en/overview.html
0
/en/page-templates.html
/en/page-templates.html
1
/en/query-profiles.html
/en/query-profiles.html
1
Change values in the query tensor to see difference in rank score, setting different weights for links.
Summary: The problem of comparing two lists of links is transformed into a numerical problem
of multiplying two occurrence vectors, summing co-occurrences and ranking by this sum:
Query tensors can grow large.
Applications will normally create the tensor in code using a Searcher,
also see example.
Here the document tensor is created from a weighted set -
a better way would be to store this in a tensor in the document to avoid the transformation.
Retrieval and ranking
So far in this guide, we have run the ranking function over all documents.
This is a valid use case for many applications.
However, ranking documents is generally CPU-expensive,
optimizing by reducing the candidate set will increase performance.
Example query using text matching,
dumping calculated rank features:
See the long list of rank features calculated per result.
However, the query filters on documents with "document" in the title,
so the features are only calculated for the small set of matching documents.
Running a filter like this is document retrieval. Another good example is web search -
the user query terms are used to retrieve the candidate set cheaply (from billions of documents),
then one or more ranking functions are applied to the much smaller candidate set to generate the ranked top-ten.
Another way to look at it is:
In the retrieval (recall) phase, find all relevant documents
In the ranking phase, show only relevant documents.
Still, the candidate set after retrieval can be big, a query can hit all documents.
Ranking all candidates is not possible in many applications.
Splitting the ranking into two phases is another optimization -
use an inexpensive ranking expression to sort out the least promising candidates
before spending most resources on the highest ranking candidates.
In short, use increasingly more power per document as the candidate set shrinks:
Let's try the same query again, with a two-phase rank-profile that also does an explicit rank score cutoff:
Note how using rank-profile inherits is a smart way to define functions once,
then use in multiple rank-profiles.
Read more about schema inheritance.
Here, num_inlinks and rank_score are defined in a rank profile we used earlier:
In the results, observe that no document has a rankingExpression(num_inlinks) less than or equal to 10.0,
meaning all such documents were purged in the first ranking phase due to the rank-score-drop-limit.
Normally, the rank-score-drop-limit is not used, as the total-keep-rank-count is most important.
Read more in the reference.
For a dynamic limit, pass a ranking feature like query(threshold)
and use an if statement to check if the score is above the threshold or not -
if below, assign -1 (something lower than the rank-score-drop-limit) and have it dropped.
Read more in ranking expressions.
Two-phased ranking is a performance optimization - this guide is about functionality,
so the rest of the examples will only be using one ranking phase.
Read more in first-phase.
Retrieval: AND, OR, weakAnd
This guide will not go deep in query operators in the retrieval phase,
see query-api for details.
Consider a query like "vespa documents about ranking and retrieval".
A query AND-ing these terms hits less than 3% of the document corpus,
missing some of the documents about ranking and retrieval:
Using a "weak AND" can address the problems of too few (AND) or too many (OR) hits in the retrieval phase.
Think of it as an optimized OR, where the least relevant candidates are discarded from further evaluation.
To find the least relevant candidates, a simple scoring function is used:
Note that this blurs the distinction between filtering (retrieval) and ranking a little -
here the weakAnd does both filtering and ranking
to optimize the number of candidates for the later rank phases.
The default rank-profile is used: