pub struct VectorScanConfig {
pub hnsw: HnswIterativeScan,
pub ivfflat: IvfflatIterativeScan,
pub ef_search: Option<u32>,
}Expand description
pgvector scan settings applied to every connection a pool opens (#1116).
Lowered into the PostgreSQL startup options packet for the same reason
SearchPath is: a pooled SET configures one session out of N, and misses
every connection the pool opens later. Riding the startup packet costs no
round trip and survives DISCARD ALL.
⚠ Safe on a database without pgvector. A two-part GUC name is accepted as a placeholder when no extension has claimed it, so the connection succeeds and the value simply never takes effect — verified against a database with the extension absent. The same mechanism covers a pgvector older than 0.8, which defines neither GUC.
Fields§
§hnsw: HnswIterativeScanhnsw.iterative_scan.
ivfflat: IvfflatIterativeScanivfflat.iterative_scan.
ef_search: Option<u32>hnsw.ef_search, or None to leave pgvector’s default of 40.
⚠ iterative_scan alone does not guarantee k rows, and on some
corpora it is not even the binding constraint. Measured on this
repository’s rig — 20 000 rows × 64 dimensions of uniform-random vectors,
a filter matching 1%, k = 10, three independently generated datasets:
| configuration | rows returned |
|---|---|
iterative_scan=off (pgvector’s default) | 2, 3, 4 |
iterative_scan=strict_order, other GUCs default | 10, 5, 4 |
…plus max_scan_tuples raised 100× | 10, 5, 4 — no change |
…plus ef_search=1000 instead | 10, 10, 10 |
iterative_scan=off and ef_search=1000 | 10, 10, 10 |
So ef_search — the size of the candidate list the graph search keeps —
is what decides whether ten members of a 1% subset are found at all, and
max_scan_tuples (which #1314 was filed against) changed nothing.
Uniform-random high-dimensional vectors are the adversarial case, and the
benchmark in benches/vector_filtered_ann.sql reports recall 1.00 from
iterative_scan alone on its own corpus — which is the point: which
knob binds depends on the data, so both have to be reachable.
Left unset by default deliberately. iterative_scan costs nothing on an
unfiltered search (measured: recall already 1.000, timings tie), so
naming it is free. ef_search is a latency/recall trade paid by every
search on the deployment, filtered or not, and its right value is a
property of the corpus. FraiseQL will not choose it for an operator; it
makes it reachable and says, above, how to tell that it is the one to
reach for.
Implementations§
Source§impl VectorScanConfig
impl VectorScanConfig
Sourcepub fn startup_fragments(self) -> Vec<String>
pub fn startup_fragments(self) -> Vec<String>
The -c fragments these settings contribute to the startup packet.
Empty when both are Off — an operator who
turned the feature off gets pgvector’s own default rather than an
explicit off, so the server’s or the database’s own ALTER DATABASE
setting still applies. Writing -c hnsw.iterative_scan=off would
override such a setting, which is not what “leave it alone” means.
Trait Implementations§
Source§impl Clone for VectorScanConfig
impl Clone for VectorScanConfig
Source§fn clone(&self) -> VectorScanConfig
fn clone(&self) -> VectorScanConfig
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for VectorScanConfig
Source§impl Debug for VectorScanConfig
impl Debug for VectorScanConfig
Source§impl Default for VectorScanConfig
impl Default for VectorScanConfig
Source§fn default() -> VectorScanConfig
fn default() -> VectorScanConfig
Source§impl<'de> Deserialize<'de> for VectorScanConfig
impl<'de> Deserialize<'de> for VectorScanConfig
Source§fn deserialize<__D>(
__deserializer: __D,
) -> Result<VectorScanConfig, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(
__deserializer: __D,
) -> Result<VectorScanConfig, <__D as Deserializer<'de>>::Error>where
__D: Deserializer<'de>,
impl Eq for VectorScanConfig
Source§impl PartialEq for VectorScanConfig
impl PartialEq for VectorScanConfig
Source§impl Serialize for VectorScanConfig
impl Serialize for VectorScanConfig
Source§fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
fn serialize<__S>(
&self,
__serializer: __S,
) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>where
__S: Serializer,
impl StructuralPartialEq for VectorScanConfig
Auto Trait Implementations§
impl Freeze for VectorScanConfig
impl RefUnwindSafe for VectorScanConfig
impl Send for VectorScanConfig
impl Sync for VectorScanConfig
impl Unpin for VectorScanConfig
impl UnsafeUnpin for VectorScanConfig
impl UnwindSafe for VectorScanConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.