Search

SingleStore Hamming distance

문서 번호: 11-4260033

Document Information

최초 작성일 : 2026.02.04
최종 수정일 : 2026.02.04
이 문서는 아래 버전을 기준으로 작성되었습니다.
Singlestore : 9.0.18
Rust: 1.93.0

Goal

Rust 기반 Wasm UDF를 사용하여 SingleStore에서 Hamming distance를 구현합니다.

Hamming Distance 개요

벡터 검색에서 검색 성능과 정확도를 최적화 하려면 적절한 distance metric을 선택하는 것이 중요합니다. Euclidean distance와 Cosine distance가 일반적으로 사용되지만, 데이터 표현 방식과 사용 사례에 따라 Hamming distance가 고유한 이점을 제공합니다.
Hamming distance는 동일한 길이를 가진 두 binary vector 간에 서로 다른 bit의 개수를 계산합니다.
이 metric은 크기 차이(numerical distance)보다 bit mismatch(비트의 불일치)가 중요한 경우에 적합합니다.
주요 응용 분야로는 텍스트 처리, 코드의 오류 검출, DNA 서열 분석 등이 있습니다. 부동소수점 연산이 필요한 Euclidean distance나 cosine distance와 달리, Hamming distance는 binary 값에 대해 연산을 수행하므로 연산 비용이 더 낮습니다.

동작 방법

Hamming distance는 두 binary vector의 각 byte 쌍에 XOR(Exclusive OR) 연산을 수행한 후, 서로 다른 bit의 개수를 계산(popcount)하여 구합니다. 총 count는 두 vector가 얼마나 다른지를 나타냅니다.

Hamming Distance 예시

다음은 두 개의 4-byte(32-bit) vector를 비교하는 예시입니다.
vector 1 (FFFFAFDF) = 11111111 11111111 10101111 11011111
vector 2 (ABCCFFDF) = 10101011 11001100 11111111 11011111
**예시 1:** vector1 (hex) : F F F F A F D F vector1 (bin) : 1111 1111 | 1111 1111 | 1010 1111 | 1101 1111 vector2 (hex) : A B C C F F D F vector2 (bin) : 1010 1011 | 1100 1100 | 1111 1111 | 1101 1111 ------------------------------------------------------------- XOR result : 0101 0100 | 0011 0011 | 0101 0000 | 0000 0000 Bit diff : (3) | (4) | (2) | (0) ------------------------------------------------------------- Hamming Distance = 9 (3 + 4 + 2 + 0) **예시 2:** Query1 (hex) : FF FF AF DF Query1 (bin) : 1111 1111 | 1111 1111 | 1010 1111 | 1101 1111 Query2 (hex) : FF FF AF DF Query2 (bin) : 1111 1111 | 1111 1111 | 1010 1111 | 1101 1111 ------------------------------------------------------------- XOR result : 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000 Bit diff : (0) | (0) | (0) | (0) ------------------------------------------------------------- Hamming Distance = 0 (0 + 0 + 0 + 0)
Plain Text
복사
참고: 두 vector가 동일하면 XOR 결과가 모두 0이 되어 Hamming distance는 0이 됩니다. distance가 낮을수록 유사도가 높습니다.

SingleStore Hamming distance

SingleStore의 기본 vector 함수는 Euclidean distance, cosine distance와 같은 일반적인 distance metric을 지원하지만, Hamming distance나 bit vector type은 지원하지 않습니다. 이 제한을 해결하기 위해 binary vector를 BLOB으로 저장하고 Wasm UDF를 사용하여 Hamming distance를 계산할 수 있습니다.

구현 가이드

Step 1: Rust 설치

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $ rustc --version -bash: rustc: command not found # 세션을 재시작한 후 설치 확인 $ exec $SHELL $ rustc --version rustc 1.93.0 (254b59607 2026-01-19) $ cargo --version cargo 1.93.0 (083ac5135 2025-12-15) # WebAssembly target 및 wit-bindgen CLI 추가 $ rustup target add wasm32-wasip1 $ cargo install --git https://github.com/bytecodealliance/wit-bindgen wit-bindgen-cli
Bash
복사

Step 2: 프로젝트 구조 생성

새로운 Rust library 프로젝트를 초기화
$ cargo new hamming_wasm $ ls hamming_wasm Cargo.toml src
Bash
복사

Step 3: Cargo.toml 설정

wit-bindgen dependency를 추가
$ vi hamming_wasm/Cargo.toml [package] name = "hamming_distance" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] [dependencies] wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen.git", rev = "60e3c5b41e616fee239304d92128e117dd9be0a7" }
TOML
복사

Step 4: WIT Interface 정의 (hamming.wit)

SingleStore에서 Wasm module을 호출할 때 사용할 함수 signature를 정의합니다.
이 함수는 byte_length parameter와 두 개의 binary vector를 byte array로 받습니다.
byte_length를 조정하여 전체 byte를 비교(full comparison)하거나 처음 N byte만 비교(partial comparison)할 수 있습니다.
$ vi hamming_wasm/hamming.wit hamming-distance: func(byte-length: s32, a: list<u8>, b: list<u8>) -> s32
Bash
복사

Step 5: Rust 소스 코드 구현 (src/lib.rs)

이 코드는 입력 길이를 검증하고, 각 byte 쌍에 XOR 연산을 수행한 후, 서로 다른 bit 개수를 계산하고 총합을 반환합니다.
$ vi hamming_wasm/src/lib.rs wit_bindgen_rust::export!("hamming.wit"); struct Hamming; impl hamming::Hamming for Hamming { fn hamming_distance(byte_length: i32, a: Vec<u8>, b: Vec<u8>) -> i32 { let num_bytes = byte_length as usize; if a.len() < num_bytes || b.len() < num_bytes { return -1; } // XOR each byte pair, count the different bits, sum total let distance: u32 = a.iter() .zip(b.iter()) .take(num_bytes) .map(|(&x, &y)| (x ^ y).count_ones()) .sum(); distance as i32 } }
Rust
복사

Step 6: Rust 코드를 WebAssembly로 컴파일

프로젝트를 컴파일합니다.
컴파일된 module은 target/wasm32-wasip1/release/hamming_distance.wasm에 생성됩니다.
$ cd hamming_wasm $ cargo build --target wasm32-wasip1 --release --lib Compiling proc-macro2 v1.0.106 Compiling pulldown-cmark v0.8.0 Compiling tinyvec_macros v0.1.1 Compiling anyhow v1.0.100 Compiling tinyvec v1.10.0 Compiling unicode-ident v1.0.22 Compiling quote v1.0.44 Compiling bitflags v1.3.2 Compiling unicase v2.9.0 Compiling memchr v2.7.6 Compiling unicode-normalization v0.1.25 Compiling id-arena v2.3.0 Compiling unicode-xid v0.2.6 Compiling unicode-segmentation v1.12.0 Compiling syn v1.0.109 Compiling wit-bindgen-gen-rust-wasm v0.1.0 (https://github.com/bytecodealliance/wit-bindgen.git?rev=60e3c5b41e616fee239304d92128e117dd9be0a7#60e3c5b4) Compiling heck v0.3.3 Compiling syn v2.0.114 Compiling wit-parser v0.1.0 (https://github.com/bytecodealliance/wit-bindgen.git?rev=60e3c5b41e616fee239304d92128e117dd9be0a7#60e3c5b4) Compiling wit-bindgen-gen-core v0.1.0 (https://github.com/bytecodealliance/wit-bindgen.git?rev=60e3c5b41e616fee239304d92128e117dd9be0a7#60e3c5b4) Compiling wit-bindgen-gen-rust v0.1.0 (https://github.com/bytecodealliance/wit-bindgen.git?rev=60e3c5b41e616fee239304d92128e117dd9be0a7#60e3c5b4) Compiling wit-bindgen-rust-impl v0.1.0 (https://github.com/bytecodealliance/wit-bindgen.git?rev=60e3c5b41e616fee239304d92128e117dd9be0a7#60e3c5b4) Compiling async-trait v0.1.89 Compiling wit-bindgen-rust v0.1.0 (https://github.com/bytecodealliance/wit-bindgen.git?rev=60e3c5b41e616fee239304d92128e117dd9be0a7#60e3c5b4) Compiling hamming_distance v0.1.0 (/home/opc/hamming_wasm) Finished `release` profile [optimized] target(s) in 3.45s
Bash
복사

Step 7: SingleStore에 배포

Wasm module을 배포하기 위한 hamming_func.sh를 생성한다. 이 script는 컴파일된 .wasm 파일을 읽어 base64로 인코딩한 후 CREATE FUNCTION 문을 실행합니다.
vi ./hamming_func.sh #!/bin/bash HOST="localhost" USER="root" PASSWORD="1" DB="db1" WASM_FILE="~/hamming_wasm/target/wasm32-wasip1/release/hamming_distance.wasm" # Generate base64 using openssl BASE64_DATA=$(openssl base64 -A -in "$WASM_FILE") # Execute SQL singlestore -h "$HOST" -u "$USER" -p"$PASSWORD" "$DB" <<EOF CREATE OR REPLACE FUNCTION hamming_distance( byte_length INT NOT NULL, a BLOB NOT NULL, b BLOB NOT NULL ) RETURNS INT NOT NULL AS WASM ABI CANONICAL FROM BASE64 '$BASE64_DATA' USING EXPORT 'hamming-distance'; EOF echo "Function Created"
Bash
복사
배포 후 함수가 생성되었는지 확인
# SingleStore 실행 $ use db1; singlestore> show functions; +------------------+-----------------------+---------+-------------+--------------+------+---------+ | Functions_in_db1 | Function Type | Definer | Data Format | Runtime Type | Link | Options | +------------------+-----------------------+---------+-------------+--------------+------+---------+ | hamming_distance | User Defined Function | root@% | | Wasm | | | +------------------+-----------------------+---------+-------------+--------------+------+---------+ 1 row in set (0.00 sec)
SQL
복사

사용 예시

테이블 설정

Binary vector 데이터를 BLOB으로 저장하는 테이블을 생성
singlestore> create table t1 ( id int, v blob not null ); --테스트 vector Insert(각 hex string = 4 bytes = 32 bits) singlestore> insert into t1 (id, v) values (1, unhex('FFFFFFFF')), (2, unhex('ABCCFFDF')), (3, unhex('FF00FF00')), (4, unhex('FFFFAFDF')); Query OK, 3 rows affected (0.03 sec)
SQL
복사

Case 1: Full Vector Comparison

query vector와 전체 4 byte를 비교하여 가장 유사한 항목 찾기
singlestore> set @query_vec = unhex('FFFFAFDF'); singlestore> select id, hamming_distance(4, v, @query_vec) as dist from t1 order by dist asc; +------+------+ | id | dist | +------+------+ | 4 | 0 | -- 가장 유사함 | 1 | 3 | | 2 | 9 | | 3 | 17 | -- 가장 유사하지 않음 +------+------+ 4 rows in set (0.03 sec)
SQL
복사

Case 2: Partial Vector Comparison

byte_length parameter를 사용하여 vector의 일부 byte만 비교할 수 있습니다.
아래 예시에서는 각 vector의 2번째 byte부터 2 byte만 추출하여 비교했습니다.
참고: 이 예시에서는 간단하게 substring을 사용하였으나, Wasm 코드를 확장하여 offset을 내부에서 처리할 수도 있습니다. use case에 따라 성능 trade-off를 고려하여 선택하시면 됩니다.
singlestore> set @query_vec = unhex('CCFF'); singlestore> select id, hamming_distance(2, substring(v, 2, 2), @query_vec) AS dist from t1 order by dist asc; +------+------+ | id | dist | +------+------+ | 2 | 0 | | 3 | 4 | | 1 | 4 | | 4 | 6 | +------+------+ 4 rows in set (0.00 sec)
SQL
복사

References

History

일자
작성자
비고
2026.02.04
mike
최초작성