[DMDB] Notes from solved tasks

This commit is contained in:
2026-07-27 08:39:47 +02:00
parent 181e9c9f7b
commit d197d01f24
4 changed files with 33 additions and 1 deletions
Binary file not shown.
@@ -1,6 +1,16 @@
Vector search is for example used in Semantic Search and of course search engines. Vector search is for example used in Semantic Search and of course search engines.
It is also used to find relevant data to augment an LLM prompt (Deep Research or whatever that type of feature is called). It is also used to find relevant data to augment an LLM prompt (Deep Research or whatever that type of feature is called).
We have at least four metrics for the quality of results:
\begin{itemize}
\item \bi{Recall}: relevant items retrieved by the vector search ($R$) divided by all relevant items ($T$), so $R \div T$. The closer to $1$, the better
\item \bi{Cosine Similarity} $S_C$: The cosine of the angle between the two vectors. Values range from $-1$ to $1$ and the closer to $1$, the better (higher = better)
\item \bi{Cosine Distance} $D_C$: defined as $1 - S_C$, values range from $0$ to $2$ and the closer to $0$, the better (lower = better)
\item \bi{Euclidian distance}: The norm of the vector between the two vectors. Values are from $0$ to $\8$, the lower the better.
\end{itemize}
$S_C(A, B) = \frac{A \cdot B}{||A|| \cdot ||B||}$, a
\subsection{Trees/Clustering} \subsection{Trees/Clustering}
Since nearest neighbour search (NNS) is not viable for large scale datasets (which they typically are), Since nearest neighbour search (NNS) is not viable for large scale datasets (which they typically are),
we use clustering algorithms such as K-Means to find $K$ cluster centroids. we use clustering algorithms such as K-Means to find $K$ cluster centroids.
@@ -13,3 +23,11 @@ Still, Vector Search is a very expensive operation due to the large number of ve
with $n$ being the number of vectors to search through. with $n$ being the number of vectors to search through.
On insert, we search the the closest centroid and simply assign the vector to that cluster. On insert, we search the the closest centroid and simply assign the vector to that cluster.
\subsubsection{Inverted File}
A not (directly, as far as I can tell) covered, but very much relevant index is the IVF index (Inverted File).
It works similarly to a normal clustered index, just that each centroid holds an \textit{inverted list} of assigned vectors.
The \texttt{nlist} parameter defines the number of coarse clusters. The larger, the shorter the lists are, the (typically and up to a point) faster the scans are,
but training / constructing it takes longer and it uses more RAM.
\texttt{nprobe} sets the number of items to retrieve on each query, so for instance, setting it to one,
we will only probe (access / retrieve) the nearest centroid's list.
@@ -12,6 +12,8 @@ Here we prune an edge $(u, v)$ if there exist edges $(u, w)$ and $(w, v)$, such
Important is that both conditions have to be met, as the goal is to remove the longest redundant edge from the graph. Important is that both conditions have to be met, as the goal is to remove the longest redundant edge from the graph.
This is done using a greedy algorithm. This is done using a greedy algorithm.
Higher values of \texttt{ef\_construction} generally improves the quality of the index at the cost of slower index construction.
\subsubsection{Search} \subsubsection{Search}
We note that greedy search always makes progress in this index because the graph stays navigable. We note that greedy search always makes progress in this index because the graph stays navigable.
@@ -25,7 +27,9 @@ Traversal of the layer costs $\tco{M_L}$, with $M_L$ the number of edges on laye
Higher up layers have fewer edges, thus making traversal cheap. Higher up layers have fewer edges, thus making traversal cheap.
The parameter \texttt{ef\_search} controls the recall vs latency. The parameter \texttt{ef\_search} controls the recall vs latency.
Set to $1$ it is approximately greedy, for $\texttt{ef\_search} \gg 1$ means more effort, i.e. more vectors visited. Set to $1$ it is approximately greedy, for $\texttt{ef\_search} \gg 1$ means more effort, i.e. more vectors visited,
but also increases recall.
\paragraph{Beam Search} \paragraph{Beam Search}
This is another greedy search algorithm, which chooses the next node to visit from a beam of size $N$. This is another greedy search algorithm, which chooses the next node to visit from a beam of size $N$.
@@ -12,6 +12,7 @@ Indices are typically built on unfiltered data. Thus, we need to think about the
This is a recall and performance challenge, because if $K' \gg K$, then we have a lot of wasted effort. This is a recall and performance challenge, because if $K' \gg K$, then we have a lot of wasted effort.
If on the other hand $K' > K$ and thus $\sigma(K') < K$, then we have low recall. If on the other hand $K' > K$ and thus $\sigma(K') < K$, then we have low recall.
\end{itemize} \end{itemize}
So, if the selectivity of the filter is high, then pre-filtering is better, if it is low, then use post-filtering.
One way around this issue is to apply an \textit{inline filter}, i.e. during \acrshort{ann} search, we do vector search, evaluate the stopping condition and apply the filter. One way around this issue is to apply an \textit{inline filter}, i.e. during \acrshort{ann} search, we do vector search, evaluate the stopping condition and apply the filter.
This gives us $K$ rows directly and a handy performance uplift to go along with it. This gives us $K$ rows directly and a handy performance uplift to go along with it.
@@ -52,6 +53,15 @@ A further optimization is to change how much of the set we re-score vs how much
Not all dataset and query combinations are equally easy, and filters also change the difficulty. Not all dataset and query combinations are equally easy, and filters also change the difficulty.
\subsubsection{Quantization}
The total storage usage of course is always $N \cdot c$, where $N$ is the number of vectors and $c$ is the cost per vector, computed as follows:
\begin{itemize}
\item \bi{Scalar-Quantization} (SQ): $c = i + d \cdot m$, where $d$ is the number of dimensions of the vector and $m$ is the byte count per dim.
\item \bi{Product Quantization} (PQ): $c = i + q$, with $i$ the cost of the vector ID and $q = m \ceil{\log_2(k) / 8}$ bytes, with $m$ the number of subvectors,
and $k$ the codebook entry count. Remember that we divide by 8 to get bytes, as the $\log_2(k)$ gives us the number of bits.
\end{itemize}
\subsubsection{Filter agnosticism} \subsubsection{Filter agnosticism}
Filter agnosticism isn't just a single type, it's a spectrum. Filter agnosticism isn't just a single type, it's a spectrum.