hora

Library Listed Dormant

Hora Search Everywhere

Checked · Sources

Downloads
1,741
Dependents
4
Stars
2,655
Forks
77
Contributors
6
Commits
65
Latest release
0.1.1 ·

About

From the project README ·

English | Français | 日本語 | 한국어 | Русский | 中文

Hora

[Homepage] [Document] [Examples]

Hora Search Everywhere!

Hora is an approximate nearest neighbor search algorithm (wiki) library. We implement all code in Rust🦀 for reliability, high level abstraction and high speeds comparable to C++.

Hora, 「ほら」 in Japanese, sounds like [hōlə], and means Wow, You see! or Look at that!. The name is inspired by a famous Japanese song 「小さな恋のうた」.

Demos

👩 Face-Match [online demo], have a try!

🍷 Dream wine comments search [online demo], have a try!

Read the full README

Features

  • Performant ⚡️

    • SIMD-Accelerated (packed_simd)
    • Stable algorithm implementation
    • Multiple threads design
  • Supports Multiple Languages ☄️

    • Python
    • Javascript
    • Java
    • Go (WIP)
    • Ruby (WIP)
    • Swift (WIP)
    • R (WIP)
    • Julia (WIP)
    • Can also be used as a service
  • Supports Multiple Indexes 🚀

    • Hierarchical Navigable Small World Graph Index (HNSWIndex) (details)
    • Satellite System Graph (SSGIndex) (details)
    • Product Quantization Inverted File(PQIVFIndex) (details)
    • Random Projection Tree(RPTIndex) (LSH, WIP)
    • BruteForce (BruteForceIndex) (naive implementation with SIMD)
  • Portable 💼

    • Supports WebAssembly
    • Supports Windows, Linux and OS X
    • Supports IOS and Android (WIP)
    • Supports no_std (WIP, partial)
    • No heavy dependencies, such as BLAS
  • Reliability 🔒

    • Rust compiler secures all code
    • Memory managed by Rust for all language libraries such as Python's
    • Broad testing coverage
  • Supports Multiple Distances 🧮

    • Dot Product Distance
    • Euclidean Distance
    • Manhattan Distance
    • Cosine Similarity
  • Productive ⭐

    • Well documented
    • Elegant, simple and easy to learn API

Installation

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

Benchmarks

by aws t2.medium (CPU: Intel(R) Xeon(R) CPU E5-2686 v4 @ 2.30GHz) more information

Examples

Rust example [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
    );
}

thank @vaaaaanquish for this complete pure Rust 🦀 image search example, For more information about this example, you can click Pure Rust な近似最近傍探索ライブラリ hora を用いた画像検索を実装する

Python example [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 example [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 example [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;
}

Roadmap

  • [ ] Full test coverage
  • [ ] Implement EFANNA algorithm to achieve faster KNN graph building
  • [ ] Swift support and iOS/macOS deployment example
  • [ ] Support R
  • [ ] support mmap

Related Projects and Comparison

  • Faiss, Annoy, ScaNN:

    • Hora's implementation is strongly inspired by these libraries.
    • Faiss focuses more on the GPU scenerio, and Hora is lighter than Faiss (no heavy dependencies).
    • Hora expects to support more languages, and everything related to performance will be implemented by Rust🦀.
    • Annoy only supports the LSH (Random Projection) algorithm.
    • ScaNN and Faiss are less user-friendly, (e.g. lack of documentation).
    • Hora is ALL IN RUST 🦀.
  • Milvus, Vald, Jina AI

    • Milvus and Vald also support multiple languages, but serve as a service instead of a library
    • Milvus is built upon some libraries such as Faiss, while Hora is a library with all the algorithms implemented itself

Contribute

We appreciate your participation!

We are glad to have you participate, any contributions are welcome, including documentations and tests. You can create a Pull Request or Issue on GitHub, and we will review it as soon as possible.

We use GitHub issues for tracking suggestions and bugs.

Clone the repo
git clone https://github.com/hora-search/hora
Build
cargo build
Test
cargo test --lib
Try the changes
cd examples
cargo run

License

The entire repository is licensed under the Apache License.

Runs on
GPU support unknown
What shows it
  • no dependency or feature matches a backend row
Native code
None found
  • No native code found
Python bindings
No Python binding crate found
License
Apache-2.0

Compare with similar projects

Order: strongest tier first, then most downloads, then name, with unmeasured values last. A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. ML Rust runs this catalogue, so its closest project always gets a row.

hora beside the projects that share a topic with it
ProjectDownloadsDependentsStarsLatest releaseRuns on (GPU)Native codeLicense
hora This page Listed Dormant

Hora Search Everywhere

1,741 downloads over 30 days 4 2,655 0.1.1 GPU support unknown No native code found Apache-2.0
usearch Featured

Smaller & Faster Single-File Vector Search Engine from Unum

242,089 downloads over 30 days 70 4,373 2.26.6 GPU support unknown Binds native code: cxx, link-cplusplus, numkong (feature numkong). Build uses a native toolchain: cxx-build Apache-2.0
qdrant App Featured

Qdrant - High-performance, massive-scale Vector Database and Vector Search Engine for the next generation of AI. Also available in the cloud https://cloud.qdrant.io/

34,017 binary downloads per release Not applicable 35,478 Not measured Not measured Apache-2.0
pgvectorscale App Listed

Postgres extension for vector search (DiskANN), complements pgvector for performance and scale. Postgres OSS licensed.

33,328 binary downloads per release Not applicable 3,161 Not measured Not measured PostgreSQL
faiss-rs Listed

High-level bindings for Faiss, the vector similarity search engine

19,449 downloads over 30 days 5 250 0.13.0 GPU support unknown Binds native code: faiss-sys, faiss_c. Build uses a native toolchain: cmake (feature static) Apache-2.0 OR MIT
splintr Listed

Tokenizer for Rust and Python: pure Rust by default, with 18 bundled vocabularies and four backends covering BPE, SentencePiece and WordPiece. Its output matches Hugging Face tokenizers id for id on 14 model families, including GPT-2, Qwen, Whisper, T5 and BERT.

Python bindings

8,204 downloads over 30 days 7 63 0.22.2 GPU support unknown Binds native code: pcre2-sys (feature pcre2) MIT
vpsearch Listed Dormant

Vantage Point Tree search algorithm for fast nearest neighbour search in multi-dimensional metric spaces.

919 downloads over 30 days 2 32 2.1.0 GPU support unknown No native code found BSD-2-Clause
Why ListedNo archive, New or Featured rule places it, so it is Listed.

What it lacks for Featured

  • It has 2 active dependents and 1 new dependents in 365 days. Featured needs 11 active dependents or 9 new dependents in 365 days. The repository route reads 2,655 stars, 77 forks and 6 contributors. It needs 4,539 stars, 434 forks and 79 contributors together.
  • The project is dormant and not finished. Dormancy rule

What else the check found

  • The last activity is on 23 Oct 2021, 1843 days ago. That reaches the 365 days the rules expect, so the project is dormant. Dormancy rule
  • The oldest outside issue waits 1957 days for a reply, past the limit of 270. No maintainer replied in 365 days. Rot signals rule
  • The latest release requires the deprecated dependency bincode. RUSTSEC-2025-0141 Rot signals rule
  • The project is dormant with 2 rot signals, which reaches the limit of 2. This is dead check 1 of 2, so the entry is not yet archived. Dead rule

Not measured: Latest release fails cargo check.

Exact rules: Listed, Featured library. The check on applied thresholds version 9.

Every rule outcome, as the check records it
  • expected-interval: version 0.1.1 base 300, capped at 2 releases = 100, raised to the 365-day floor: E = 365 days
  • dormancy: last activity 2021-10-23, 1843 days ago, E = 365: dormant
  • rot: oldest unanswered issue 1957 days (limit 270), no maintainer reply in 365 days
  • rot: deprecated requirement `bincode (RUSTSEC-2025-0141, https://rustsec.org/advisories/RUSTSEC-2025-0141.html)`
  • dead: dormant with 2 rot signals (limit 2): dead on check 1 of 2, not yet archived
  • featured: not featured: active_users 2 < 11 and new_adopters 1 < 9 and repository route stars 2655 (needs 4539), forks 77 (needs 434), contributors 6 (needs 79); dormant and not stable
  • listed: listed: no archive, new or featured rule applies

Measurements and sources

Each signal row shows the raw value, its source and the fetch date. The Sources list gathers every distinct source on this page. Movement needs more history.

Sources6 sources
Adoption2 active dependents, 1 new dependents in 365 days1 not measured
Adoption measurements
SignalValueSourceFetchedCounts
Active dependents2crates.io database dumpYes
New dependents (365 days)1crates.io database dumpYes
Peak active dependents2crates.io database dumpYes
Active dependents as a share of the peak1crates.io database dumpYes
Binary downloads per releaseNot measuredYes
MaintenanceLatest human commit: 5 years ago3 not measured
Maintenance measurements
SignalValueSourceFetchedCounts
Latest human commit2021-10-23GitHub repositoryYes
Latest release2021-08-07crates.io database dumpYes
First release2021-07-24crates.io database dumpYes
Latest version0.1.1crates.io database dumpYes
Days the oldest outside issue waits for a reply1957GitHub repositoryYes
Maintainer replies over 365 days0GitHub repositoryYes
Repository archivedfalseGitHub repositoryYes
Repository gonefalseGitHub repositoryYes
Release commit or manifest in the repotruecrates.io packageYes
Published docstruecrates.io database dumpYes
Latest release fails cargo checkNot measuredYes
Build check dateNot measuredYes
Build check toolchainNot measuredYes
SecurityUnpatched vulnerabilities: none
Security measurements
SignalValueSourceFetchedCounts
Unpatched vulnerabilities past the grace windownoneRustSec advisory databaseYes
RustSec unmaintained advisorynoneRustSec advisory databaseYes
Deprecation noticenonecrates.io database dumpYes
Deprecated requirementbincode (RUSTSEC-2025-0141, https://rustsec.org/advisories/RUSTSEC-2025-0141.html)crates.io database dumpYes
Distribution2 releases, 1,741 downloads over 30 days5 not measured
Distribution measurements
SignalValueSourceFetchedCounts
Releases2crates.io database dumpYes
Downloads over 30 days1741crates.io database dumpYes
Binary downloads over the last 3 releasesNot measuredYes
Homebrew installs on request over 365 daysNot measuredYes
Repology repository familiesNot measuredYes
Docker pull growth over 90 daysNot measuredYes
Docker pulls at the growth baselineNot measuredYes
Every version a prereleasefalsecrates.io database dumpYes
Every version 0.0.xfalsecrates.io database dumpYes
Every version yankedfalsecrates.io database dumpYes
Crate deleted from crates.iofalsecrates.io database dumpYes
Repository2,655 stars, 77 forks, 6 contributors, 65 commits. Stars alone never qualify a project.
Repository measurements
SignalValueSourceFetchedCounts
GitHub stars2655GitHub repositoryYes — one part of the repository route
GitHub forks77GitHub repositoryYes — one part of the repository route
Contributors with a GitHub account6GitHub contributorsYes — one part of the repository route
Commits on the default branch65GitHub repositoryNo
Repository's main crate left out of the entrynonecrates.io database dumpYes
Facts that never count
Facts that never count measurements
SignalValueSourceFetchedCounts
LicenseApache-2.0crates.io database dumpNo
Runs on, from listed crates and their direct dependenciesGPU support unknowncrates.io database dumpNo
What shows each backendno dependency or feature matches a backend rowcrates.io database dumpNo
Native code, from listed crates and their dependenciesNo native code foundcrates.io database dumpNo
Python bindings, from direct dependencies of listed cratesNo Python binding crate foundcrates.io database dumpNo
Crates that depend on a listed crate directly4crates.io database dumpNo

Corrections and review history

Report a correction

No correction applies to this entry.

Judgments

A judgment enters only through an approved issue and a merged pull request.

No judgment applies to this entry.