Skip to main content
QBit 데이터 타입은 더 빠른 근사 벡터 검색을 위해 벡터 저장 방식을 재구성합니다. 각 벡터의 요소를 함께 저장하는 대신, 모든 벡터에서 동일한 비트 위치끼리 묶어 저장합니다. 이 방식은 벡터를 전체 정밀도로 저장하면서도, 검색 시점에 세밀한 양자화 수준을 선택할 수 있게 합니다. 즉, I/O를 줄이고 계산 속도를 높이기 위해 더 적은 비트를 읽거나, 더 높은 정확도를 위해 더 많은 비트를 읽을 수 있습니다. 양자화를 통해 데이터 전송량과 연산량을 줄여 속도상의 이점을 얻으면서도, 필요할 때는 원본 데이터 전체를 그대로 사용할 수 있습니다. QBit 타입의 컬럼을 선언하려면 다음 구문을 사용합니다:
  • element_type – 각 벡터 요소의 타입입니다. 허용되는 타입은 Int8, BFloat16, Float32, Float64입니다
  • dimension – 각 벡터를 구성하는 요소의 수입니다
  • stride – 선택 사항입니다. 하나의 스트림 그룹에 함께 저장되는 차원의 수입니다. 생략하면 기본값은 dimension(단일 그룹)입니다. 지정하는 경우 dimensionstride의 배수여야 하며, stridedimension보다 작을 때는 stride도 8의 배수여야 합니다. dimension개의 차원은 dimension / stride개의 연속된 그룹으로 나뉘며, 각 그룹의 비트 평면은 별도의 스트림에 저장됩니다. 따라서 처음 D개 차원에 대한 검색에서는(Dstride의 배수) 해당 차원을 포함하는 그룹의 스트림만 읽으면 되므로 Matryoshka embeddings에 유용합니다.

QBit 생성

테이블 컬럼 정의에 QBit 유형을 사용합니다:

배열을 QBit으로 변환하기

배열 길이가 QBit 차원과 일치하면 배열을 QBit으로 변환할 수 있습니다. 배열의 요소 타입이 QBit 요소 타입과 같을 필요는 없습니다. 숫자 요소 타입은 모두 자동으로 해당 타입으로 변환됩니다. 따라서 기존 embeddings 컬럼을 바로 QBit 컬럼으로 옮길 수 있습니다:
이 변환은 CAST를 사용해 명시적으로 수행할 수도 있습니다. 예를 들어 CAST(embedding AS QBit(Float32, 8))와 같습니다.

QBit를 배열로 변환하기

역변환은 비트 전치 표현에서 원래 벡터를 복원하므로, QBitArray로 캐스팅하면 저장된 값이 반환됩니다. 이는 배열을 QBit로 변환하기의 역과정입니다:
재구성된 배열은 QBit의 타입을 사용한 뒤, 각 요소를 요청된 배열 타입으로 변환합니다. 따라서 QBit(Float32, N)에서 Array(Float64)로처럼 타입까지 변경하는 cast도 동작합니다. Array -> QBit -> Array 왕복 변환은 Int8, Float32, Float64에서는 손실이 없습니다. BFloat16의 경우 BFloat16로 직접 변환한 결과와 일치하며, 손실되는 정밀도는 BFloat16 자체의 정밀도뿐입니다. 차원이 8의 배수가 아니면 내부 표현에 포함된 후행 패딩 요소가 삭제되므로, 결과에는 항상 정확히 차원개의 요소만 포함됩니다.

QBit 타입 간 변환

QBitdimension(벡터 원소 수)이 동일하게 유지되는 한 다른 QBit으로 캐스팅할 수 있습니다. element_typestride는 모두 변경할 수 있지만, dimension이 다른 QBit으로 캐스팅하면 벡터 자체가 바뀌므로 예외가 발생합니다. element_type을 변경하면 벡터를 다시 구성하고 각 원소를 새 타입으로 변환하는데, 이는 해당 Array 변환과 정확히 같습니다. 확장 변환(예: QBit(Float32, N)에서 QBit(Float64, N)으로)은 정확하게 수행되지만, 축소 변환은 축소 Array 캐스트와 마찬가지로 정밀도가 손실됩니다.
stride만 변경하고 element_type은 그대로 유지하면, 값 자체는 건드리지 않은 채 저장된 비트 평면만 다시 그룹화하므로 항상 무손실입니다:

QBit 서브컬럼

QBit는 저장된 벡터의 개별 비트 평면에 접근할 수 있는 서브컬럼 접근 패턴을 구현합니다. 각 비트 위치는 .N 구문으로 접근할 수 있으며, 여기서 N은 해당 비트 위치를 나타냅니다:
접근 가능한 서브컬럼 수는 요소 타입에 따라 달라지며, stride가 적용된 경우 stride 그룹 수에도 따라 달라집니다:
  • Int8: stride 그룹당 8개 서브컬럼 (1-8)
  • BFloat16: stride 그룹당 16개 서브컬럼 (1-16)
  • Float32: stride 그룹당 32개 서브컬럼 (1-32)
  • Float64: stride 그룹당 64개 서브컬럼 (1-64)
서브컬럼은 그룹 우선 순서를 따릅니다. 일반적으로 vec.N은 stride 그룹 (N-1) / element_size의 비트 평면 (N-1) % element_size를 읽습니다. 예를 들어 QBit(BFloat16, 4096, 1024)에서는 4096개 차원이 1024개씩 4개의 그룹으로 나뉘므로 서브컬럼은 총 64개입니다. vec.1vec.16은 첫 번째 stride 그룹(차원 1–1024)의 비트 평면이고, vec.17vec.32는 두 번째 그룹(차원 1025–2048)에 속하며, 이후도 같은 방식으로 이어집니다.

스트라이드

기본적으로 QBit는 각 비트 평면을 모든 dimension 차원에 걸친 단일 스트림으로 저장하므로, 검색 시 항상 전체 벡터의 비트 평면을 모두 읽게 됩니다. 선택적 stride 매개변수는 dimension 차원을 dimension / stride개의 연속된 그룹으로 나누고, 각 그룹의 비트 평면을 별도의 스트림에 저장합니다. 그러면 처음 D개 차원만 대상으로 검색할 때(Dstride의 배수), 해당 차원을 포함하는 그룹의 스트림만 읽으면 됩니다. 이는 앞부분 차원만으로도 더 낮은 차원의 유효한 임베딩을 구성하는 Matryoshka embeddings에 특히 유용합니다.
여기서 4096개 차원은 1024개씩 4개의 그룹으로 나뉩니다. 서브컬럼은 그룹 우선 순서를 따릅니다. 즉, BFloat16(16개의 비트 평면)에서는 vec.1vec.16이 첫 번째 stride 그룹(차원 1–1024)의 16개 비트 평면이고, vec.17vec.32는 두 번째 그룹(차원 1025–2048)에 속하며, 이후에도 같은 방식으로 이어집니다. 일반적으로 vec.N은 stride 그룹 (N-1) / element_size의 비트 평면 (N-1) % element_size를 읽습니다. 축소 차원 검색을 실행하려면 전치 거리 함수의 네 번째 인수로 읽을 차원 수를 전달하십시오(아래 참조). 참조 벡터는 최소한 그 개수만큼의 원소를 가져야 하며(이를 초과하는 뒤쪽 원소는 무시됨), 이 값은 stride의 배수여야 합니다.

벡터 검색 함수

다음은 QBit 데이터 타입을 사용하는 벡터 유사도 검색용 거리 함수입니다: stride가 적용된 QBit의 경우, 이러한 함수는 선택적인 네 번째 인수 used_dims(읽을 선행 차원의 수)를 받을 수 있으며, 이 경우 해당 차원을 포함하는 stride 그룹만 읽습니다. 참조 벡터는 최소 used_dims개의 원소를 가져야 하며(뒤에 추가된 원소는 무시되므로, 전체 크기의 쿼리 벡터를 먼저 잘라내지 않고도 축소 차원 검색에 재사용할 수 있습니다), used_dimsstride의 배수여야 합니다.
마지막 수정일 2026년 7월 23일