mirror of
https://github.com/janishutz/eth-summaries.git
synced 2026-07-27 21:29:09 +02:00
[DMDB] Notes from solved tasks
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
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).
|
||||
|
||||
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}
|
||||
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.
|
||||
@@ -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.
|
||||
|
||||
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.
|
||||
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}
|
||||
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.
|
||||
|
||||
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}
|
||||
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.
|
||||
If on the other hand $K' > K$ and thus $\sigma(K') < K$, then we have low recall.
|
||||
\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.
|
||||
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.
|
||||
|
||||
|
||||
\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}
|
||||
Filter agnosticism isn't just a single type, it's a spectrum.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user