[Homepage] [Document] [Examples]
Hora Search Everywhere!
Hora est un algorithme de recherche du voisin le plus proche approximatif (wiki). Nous implémentons tout le code dans Rust🦀
pour une fiabilité, une abstraction de haut niveau et des vitesses élevées comparables à C++
.
Hora, 「ほら」
en japonais, sonne comme [hōlə]
, et signifie Wow
, Vous voyez !
ou Regardez ça !
. Le nom est inspiré d'une célèbre chanson japonaise 「小さな恋のうた」
.
👩 Face-Match [online demo], Essaye!
🍷 Recherche de commentaires sur le vin de rêve [online demo], Essaye!
-
Performant ⚡️
- SIMD-Accelerated (packed_simd)
- Implémentation d'algorithme stable
- Multiple threads design
-
Prend en charge plusieurs langages de programmation Lib ☄️
Python
Javascript
Java
Go
(WIP)Ruby
(WIP)Swift
(WIP)R
(WIP)Julia
(WIP)- Peut également être utilisé comme un service
-
Prend en charge plusieurs index 🚀
-
Portable 💼
- Supports
WebAssembly
- Supports
Windows
,Linux
andOS X
- Supports
IOS
andAndroid
(WIP) - Supports
no_std
(WIP, partial) - Pas de dépendances lourdes, telles que
BLAS
- Supports
-
Fiabilité 🔒
- Le compilateur
Rust
sécurise tout le code - Mémoire gérée par
Rust
pour toutes les bibliothèques de langage telles quePython's
- Large couverture de test
- Le compilateur
-
Prend en charge plusieurs distances 🧮
-
Productive ⭐
- Bien documenté
- API élégante, simple et facile à apprendre
Rust
in Cargo.toml
[dependencies]
hora = "0.1.1"
Python
$ pip install horapy
Javascript (WebAssembly)
$ npm i horajs
Building from source
$ git clone https://github.com/hora-search/hora
$ cargo build
by aws t2.medium (CPU: Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz)
more information
Rust
exemple [more info]
use hora::core::ann_index::ANNIndex;
use rand::{thread_rng, Rng};
use rand_distr::{Distribution, Normal};
pub fn demo() {
let n = 1000;
let dimension = 64;
// make sample points
let mut samples = Vec::with_capacity(n);
let normal = Normal::new(0.0, 10.0).unwrap();
for _i in 0..n {
let mut sample = Vec::with_capacity(dimension);
for _j in 0..dimension {
sample.push(normal.sample(&mut rand::thread_rng()));
}
samples.push(sample);
}
// init index
let mut index = hora::index::hnsw_idx::HNSWIndex::<f32, usize>::new(
dimension,
&hora::index::hnsw_params::HNSWParams::<f32>::default(),
);
for (i, sample) in samples.iter().enumerate().take(n) {
// add point
index.add(sample, i).unwrap();
}
index.build(hora::core::metrics::Metric::Euclidean).unwrap();
let mut rng = thread_rng();
let target: usize = rng.gen_range(0..n);
// 523 has neighbors: [523, 762, 364, 268, 561, 231, 380, 817, 331, 246]
println!(
"{:?} has neighbors: {:?}",
target,
index.search(&samples[target], 10) // search for k nearest neighbors
);
}
merci @vaaaaanquish pour cette recherche complète d'images de rouille pure [exemple] (https://github.com/vaaaaanquish/rust-ann-search-example), Pour plus d'informations sur cet exemple, veuillez cliquer sur Pure Rustな近似最近傍 horaを用いた画像検索を実装する
Python
exemple [more info]
import numpy as np
from horapy import HNSWIndex
dimension = 50
n = 1000
# init index instance
index = HNSWIndex(dimension, "usize")
samples = np.float32(np.random.rand(n, dimension))
for i in range(0, len(samples)):
# add node
index.add(np.float32(samples[i]), i)
index.build("euclidean") # build index
target = np.random.randint(0, n)
# 410 in Hora ANNIndex <HNSWIndexUsize> (dimension: 50, dtype: usize, max_item: 1000000, n_neigh: 32, n_neigh0: 64, ef_build: 20, ef_search: 500, has_deletion: False)
# has neighbors: [410, 736, 65, 36, 631, 83, 111, 254, 990, 161]
print("{} in {} \nhas neighbors: {}".format(
target, index, index.search(samples[target], 10))) # search
JavaScript
exemple [more info]
import * as horajs from "horajs";
const demo = () => {
const dimension = 50;
var bf_idx = horajs.BruteForceIndexUsize.new(dimension);
// var hnsw_idx = horajs.HNSWIndexUsize.new(dimension, 1000000, 32, 64, 20, 500, 16, false);
for (var i = 0; i < 1000; i++) {
var feature = [];
for (var j = 0; j < dimension; j++) {
feature.push(Math.random());
}
bf_idx.add(feature, i); // add point
}
bf_idx.build("euclidean"); // build index
var feature = [];
for (var j = 0; j < dimension; j++) {
feature.push(Math.random());
}
console.log("bf result", bf_idx.search(feature, 10)); //bf result Uint32Array(10) [704, 113, 358, 835, 408, 379, 117, 414, 808, 826]
}
(async () => {
await horajs.default();
await horajs.init_env();
demo();
})();
Java
exemple [more info]
public void demo() {
final int dimension = 2;
final float variance = 2.0f;
Random fRandom = new Random();
BruteForceIndex bruteforce_idx = new BruteForceIndex(dimension); // init index instance
List<float[]> tmp = new ArrayList<>();
for (int i = 0; i < 5; i++) {
for (int p = 0; p < 10; p++) {
float[] features = new float[dimension];
for (int j = 0; j < dimension; j++) {
features[j] = getGaussian(fRandom, (float) (i * 10), variance);
}
bruteforce_idx.add("bf", features, i * 10 + p); // add point
tmp.add(features);
}
}
bruteforce_idx.build("bf", "euclidean"); // build index
int search_index = fRandom.nextInt(tmp.size());
// nearest neighbor search
int[] result = bruteforce_idx.search("bf", 10, tmp.get(search_index));
// [main] INFO com.hora.app.ANNIndexTest - demo bruteforce_idx[7, 8, 0, 5, 3, 9, 1, 6, 4, 2]
log.info("demo bruteforce_idx" + Arrays.toString(result));
}
private static float getGaussian(Random fRandom, float aMean, float variance) {
float r = (float) fRandom.nextGaussian();
return aMean + r * variance;
}
- Couverture complète des tests
- Implémentez l'algorithme EFANNA pour obtenir une création de graphes KNN plus rapide
- Prise en charge Swift et exemple de déploiement iOS/macOS
- Support
R
- support
mmap
-
- L'implémentation de
Hora
est fortement inspirée de ces bibliothèques. Faiss
se concentre davantage sur la scène GPU, etHora
est plus léger que Faiss (pas de dépendances lourdes).Hora
s'attend à prendre en charge plus de langues, et tout ce qui concerne les performances sera implémenté par Rust🦀.Annoy
ne prend en charge que l'algorithmeLSH (Random Projection)
.ScaNN
etFaiss
sont moins conviviaux (par exemple, manque de documentation).- Hora is ALL IN RUST 🦀.
- L'implémentation de
-
Milvus
etVald
prennent également en charge plusieurs langues, mais servent de service au lieu d'une bibliothèqueMilvus
est construit sur certaines bibliothèques telles queFaiss
, tandis queHora
est une bibliothèque avec tous les algorithmes implémentés elle-même
Nous apprécions votre aide!
Nous sommes ravis de votre participation, toutes les contributions sont les bienvenues, y compris les documentations et les tests.
Vous pouvez créer une Pull Request
ou un Issue
sur GitHub, et nous l'examinerons dès que possible.
Nous utilisons les problèmes GitHub pour suivre les suggestions et les bogues.
git clone https://github.com/hora-search/hora
cargo build
cargo test --lib
cd examples
cargo run
The entire repository is licensed under the Apache License.