1
0
mirror of https://github.com/tensorchord/pgvecto.rs.git synced 2025-08-01 06:46:52 +03:00

feat: allow user to set vbase range (#206)

* feat: allow user to set vbase range

Signed-off-by: silver-ymz <yinmingzhuo@gmail.com>

* separate the enable_vbase and vbase_range settings

Signed-off-by: silver-ymz <yinmingzhuo@gmail.com>

---------

Signed-off-by: silver-ymz <yinmingzhuo@gmail.com>
This commit is contained in:
Mingzhuo Yin
2023-12-27 14:32:23 +08:00
committed by GitHub
parent 7a2eb0a635
commit 4f60c4c824
9 changed files with 36 additions and 19 deletions

View File

@ -330,11 +330,9 @@ impl<S: G> IndexView<S> {
.map(|x| Pointer::from_u48(x.payload >> 16)) .map(|x| Pointer::from_u48(x.payload >> 16))
.collect() .collect()
} }
pub fn vbase(&self, vector: &[S::Scalar]) -> impl Iterator<Item = Pointer> + '_ { pub fn vbase(&self, vector: &[S::Scalar], range: usize) -> impl Iterator<Item = Pointer> + '_ {
assert_eq!(self.options.vector.dims as usize, vector.len()); assert_eq!(self.options.vector.dims as usize, vector.len());
let range = 86;
struct Comparer<'a, S: G> { struct Comparer<'a, S: G> {
iter: ComparerIter<'a, S>, iter: ComparerIter<'a, S>,
item: Option<HeapElement>, item: Option<HeapElement>,

View File

@ -139,43 +139,44 @@ impl InstanceView {
pub fn vbase( pub fn vbase(
&self, &self,
vector: DynamicVector, vector: DynamicVector,
range: usize,
) -> Result<impl Iterator<Item = Pointer> + '_, FriendlyError> { ) -> Result<impl Iterator<Item = Pointer> + '_, FriendlyError> {
match (self, vector) { match (self, vector) {
(InstanceView::F32Cos(x), DynamicVector::F32(vector)) => { (InstanceView::F32Cos(x), DynamicVector::F32(vector)) => {
if x.options.vector.dims as usize != vector.len() { if x.options.vector.dims as usize != vector.len() {
return Err(FriendlyError::Unmatched2); return Err(FriendlyError::Unmatched2);
} }
Ok(Box::new(x.vbase(&vector)) as Box<dyn Iterator<Item = Pointer>>) Ok(Box::new(x.vbase(&vector, range)) as Box<dyn Iterator<Item = Pointer>>)
} }
(InstanceView::F32Dot(x), DynamicVector::F32(vector)) => { (InstanceView::F32Dot(x), DynamicVector::F32(vector)) => {
if x.options.vector.dims as usize != vector.len() { if x.options.vector.dims as usize != vector.len() {
return Err(FriendlyError::Unmatched2); return Err(FriendlyError::Unmatched2);
} }
Ok(Box::new(x.vbase(&vector))) Ok(Box::new(x.vbase(&vector, range)))
} }
(InstanceView::F32L2(x), DynamicVector::F32(vector)) => { (InstanceView::F32L2(x), DynamicVector::F32(vector)) => {
if x.options.vector.dims as usize != vector.len() { if x.options.vector.dims as usize != vector.len() {
return Err(FriendlyError::Unmatched2); return Err(FriendlyError::Unmatched2);
} }
Ok(Box::new(x.vbase(&vector))) Ok(Box::new(x.vbase(&vector, range)))
} }
(InstanceView::F16Cos(x), DynamicVector::F16(vector)) => { (InstanceView::F16Cos(x), DynamicVector::F16(vector)) => {
if x.options.vector.dims as usize != vector.len() { if x.options.vector.dims as usize != vector.len() {
return Err(FriendlyError::Unmatched2); return Err(FriendlyError::Unmatched2);
} }
Ok(Box::new(x.vbase(&vector))) Ok(Box::new(x.vbase(&vector, range)))
} }
(InstanceView::F16Dot(x), DynamicVector::F16(vector)) => { (InstanceView::F16Dot(x), DynamicVector::F16(vector)) => {
if x.options.vector.dims as usize != vector.len() { if x.options.vector.dims as usize != vector.len() {
return Err(FriendlyError::Unmatched2); return Err(FriendlyError::Unmatched2);
} }
Ok(Box::new(x.vbase(&vector))) Ok(Box::new(x.vbase(&vector, range)))
} }
(InstanceView::F16L2(x), DynamicVector::F16(vector)) => { (InstanceView::F16L2(x), DynamicVector::F16(vector)) => {
if x.options.vector.dims as usize != vector.len() { if x.options.vector.dims as usize != vector.len() {
return Err(FriendlyError::Unmatched2); return Err(FriendlyError::Unmatched2);
} }
Ok(Box::new(x.vbase(&vector))) Ok(Box::new(x.vbase(&vector, range)))
} }
_ => Err(FriendlyError::Unmatched2), _ => Err(FriendlyError::Unmatched2),
} }

View File

@ -31,6 +31,7 @@ Search options are specified by PostgreSQL GUC. You can use `SET` command to app
| vectors.k | integer | Expected number of candidates returned by index. The parameter will influence the recall if you use HNSW or quantization for indexing. Default value is `64`. | | vectors.k | integer | Expected number of candidates returned by index. The parameter will influence the recall if you use HNSW or quantization for indexing. Default value is `64`. |
| vectors.enable_prefilter | boolean | Enable prefiltering or not. Default value is `off`. | | vectors.enable_prefilter | boolean | Enable prefiltering or not. Default value is `off`. |
| vectors.enable_vector_index | boolean | Enable vector indexes or not. This option is for debugging. Default value is `on`. | | vectors.enable_vector_index | boolean | Enable vector indexes or not. This option is for debugging. Default value is `on`. |
| vectors.enable_vbase | boolean | Enable vbase optimization. Default value is `off`. | | vectors.enable_vbase | boolean | Enable vbase optimization or not. Default value is `off`. |
| vectors.vbase_range | integer | Range size of vbase optimization. The larger the range, the more accurate the result, but the slower the speed. Default value is `100`. |
Note: When `vectors.enable_vbase` is enabled, prefilter does not work. Note: When `vectors.enable_vbase` is enabled, prefilter does not work.

View File

@ -136,7 +136,7 @@ fn session(worker: Arc<Worker>, mut handler: RpcHandler) -> Result<(), IpcError>
let result = worker.call_stat(id); let result = worker.call_stat(id);
handler = x.leave(result)?; handler = x.leave(result)?;
} }
RpcHandle::Vbase { id, vector, x } => { RpcHandle::Vbase { id, vbase, x } => {
use crate::ipc::server::VbaseHandle::*; use crate::ipc::server::VbaseHandle::*;
let instance = match worker.get_instance(id) { let instance = match worker.get_instance(id) {
Ok(x) => x, Ok(x) => x,
@ -146,7 +146,7 @@ fn session(worker: Arc<Worker>, mut handler: RpcHandler) -> Result<(), IpcError>
} }
}; };
let view = instance.view(); let view = instance.view();
let mut it = match view.vbase(vector) { let mut it = match view.vbase(vbase.0, vbase.1) {
Ok(x) => x, Ok(x) => x,
Err(e) => { Err(e) => {
x.error(Err(e))?; x.error(Err(e))?;

View File

@ -25,6 +25,8 @@ pub static ENABLE_PREFILTER: GucSetting<bool> = GucSetting::<bool>::new(false);
pub static ENABLE_VBASE: GucSetting<bool> = GucSetting::<bool>::new(false); pub static ENABLE_VBASE: GucSetting<bool> = GucSetting::<bool>::new(false);
pub static VBASE_RANGE: GucSetting<i32> = GucSetting::<i32>::new(100);
pub static TRANSPORT: GucSetting<Transport> = GucSetting::<Transport>::new(Transport::default()); pub static TRANSPORT: GucSetting<Transport> = GucSetting::<Transport>::new(Transport::default());
pub unsafe fn init() { pub unsafe fn init() {
@ -70,6 +72,16 @@ pub unsafe fn init() {
GucContext::Userset, GucContext::Userset,
GucFlags::default(), GucFlags::default(),
); );
GucRegistry::define_int_guc(
"vectors.vbase_range",
"The range of vbase.",
"The range size of vabse optimization.",
&VBASE_RANGE,
1,
u16::MAX as _,
GucContext::Userset,
GucFlags::default(),
);
GucRegistry::define_enum_guc( GucRegistry::define_enum_guc(
"vectors.transport", "vectors.transport",
"Transport for communicating with background worker.", "Transport for communicating with background worker.",

View File

@ -1,6 +1,7 @@
use crate::gucs::ENABLE_PREFILTER; use crate::gucs::ENABLE_PREFILTER;
use crate::gucs::ENABLE_VBASE; use crate::gucs::ENABLE_VBASE;
use crate::gucs::K; use crate::gucs::K;
use crate::gucs::VBASE_RANGE;
use crate::index::utils::from_datum; use crate::index::utils::from_datum;
use crate::ipc::client::ClientGuard; use crate::ipc::client::ClientGuard;
use crate::ipc::client::Vbase; use crate::ipc::client::Vbase;
@ -96,7 +97,7 @@ pub unsafe fn next_scan(scan: pgrx::pg_sys::IndexScanDesc) -> bool {
let mut rpc = crate::ipc::client::borrow_mut(); let mut rpc = crate::ipc::client::borrow_mut();
if ENABLE_VBASE.get() { if ENABLE_VBASE.get() {
let vbase = rpc.vbase(id, vector.clone()); let vbase = rpc.vbase(id, (vector.clone(), VBASE_RANGE.get() as _));
*scanner = Scanner::Vbase { node, vbase }; *scanner = Scanner::Vbase { node, vbase };
} else { } else {
let k = K.get() as _; let k = K.get() as _;

View File

@ -120,8 +120,12 @@ impl Rpc {
let stat::StatPacket::Leave { result } = self.socket.client_recv().friendly(); let stat::StatPacket::Leave { result } = self.socket.client_recv().friendly();
result.friendly() result.friendly()
} }
pub fn vbase(mut self: ClientGuard<Self>, id: Id, vector: DynamicVector) -> ClientGuard<Vbase> { pub fn vbase(
let packet = RpcPacket::Vbase { id, vector }; mut self: ClientGuard<Self>,
id: Id,
vbase: (DynamicVector, usize),
) -> ClientGuard<Vbase> {
let packet = RpcPacket::Vbase { id, vbase };
self.socket.client_send(packet).friendly(); self.socket.client_send(packet).friendly();
let vbase::VbaseErrorPacket { result } = self.socket.client_recv().friendly(); let vbase::VbaseErrorPacket { result } = self.socket.client_recv().friendly();
result.friendly(); result.friendly();

View File

@ -40,6 +40,6 @@ pub enum RpcPacket {
}, },
Vbase { Vbase {
id: Id, id: Id,
vector: DynamicVector, vbase: (DynamicVector, usize),
}, },
} }

View File

@ -65,9 +65,9 @@ impl RpcHandler {
socket: self.socket, socket: self.socket,
}, },
}, },
RpcPacket::Vbase { id, vector } => RpcHandle::Vbase { RpcPacket::Vbase { id, vbase } => RpcHandle::Vbase {
id, id,
vector, vbase,
x: Vbase { x: Vbase {
socket: self.socket, socket: self.socket,
}, },
@ -111,7 +111,7 @@ pub enum RpcHandle {
}, },
Vbase { Vbase {
id: Id, id: Id,
vector: DynamicVector, vbase: (DynamicVector, usize),
x: Vbase, x: Vbase,
}, },
} }