195 stable releases
Uses new Rust 2024
| new 1.8.28 | Mar 13, 2026 |
|---|---|
| 1.8.27 | Mar 7, 2026 |
| 1.8.23 | Feb 28, 2026 |
| 1.4.37 | Jan 31, 2026 |
| 0.1.0 | Jan 14, 2026 |
#129 in Database interfaces
2.5MB
58K
SLoC
Hermes Server
A high-performance gRPC search server for Hermes indexes.
Features
- Index Management: Create, delete, and manage search indexes
- Document Indexing: Stream or batch index documents
- Full-Text Search: Term queries, boolean queries, and boosting
- Document Retrieval: Get documents by ID
- Segment Management: Commit changes and force merge segments
Installation
cargo install hermes-server
Or build from source:
cargo build --release -p hermes-server
Usage
Starting the Server
hermes-server --addr 0.0.0.0:50051 --data-dir ./data
Options:
-a, --addr: Address to bind to (default:0.0.0.0:50051)-d, --data-dir: Directory for storing indexes (default:./data)
gRPC API
The server exposes two services: SearchService and IndexService.
IndexService
CreateIndex
Create a new index with a schema definition (SDL or JSON format).
rpc CreateIndex(CreateIndexRequest) returns (CreateIndexResponse);
message CreateIndexRequest {
string index_name = 1;
string schema = 2; // SDL or JSON schema
}
SDL Schema Example:
index articles {
title: text indexed stored
body: text indexed stored
author: text indexed stored
published_at: u64 indexed stored
tags: text indexed stored
}
JSON Schema Example:
{
"fields": [
{ "name": "title", "type": "text", "indexed": true, "stored": true },
{ "name": "body", "type": "text", "indexed": true, "stored": true },
{ "name": "score", "type": "f64", "indexed": false, "stored": true }
]
}
BatchIndexDocuments
Index multiple documents in a single request.
rpc BatchIndexDocuments(BatchIndexDocumentsRequest) returns (BatchIndexDocumentsResponse);
message BatchIndexDocumentsRequest {
string index_name = 1;
repeated NamedDocument documents = 2;
}
message NamedDocument {
map<string, FieldValue> fields = 1;
}
IndexDocuments (Streaming)
Stream documents for indexing.
rpc IndexDocuments(stream IndexDocumentRequest) returns (IndexDocumentsResponse);
Commit
Commit pending changes to make them searchable.
rpc Commit(CommitRequest) returns (CommitResponse);
ForceMerge
Merge all segments into one for optimal search performance.
rpc ForceMerge(ForceMergeRequest) returns (ForceMergeResponse);
DeleteIndex
Delete an index and all its data.
rpc DeleteIndex(DeleteIndexRequest) returns (DeleteIndexResponse);
SearchService
Search
Search for documents matching a query.
rpc Search(SearchRequest) returns (SearchResponse);
message SearchRequest {
string index_name = 1;
Query query = 2;
uint32 limit = 3;
uint32 offset = 4;
repeated string fields_to_load = 5;
}
Query Types:
- TermQuery: Match a specific term in a field
- BooleanQuery: Combine queries with must/should/must_not
- BoostQuery: Boost the score of a query
GetDocument
Retrieve a document by its ID.
rpc GetDocument(GetDocumentRequest) returns (GetDocumentResponse);
GetIndexInfo
Get information about an index (document count, segments, schema).
rpc GetIndexInfo(GetIndexInfoRequest) returns (GetIndexInfoResponse);
Field Types
| Type | Description |
|---|---|
text |
Full-text searchable string |
u64 |
Unsigned 64-bit integer |
i64 |
Signed 64-bit integer |
f64 |
64-bit floating point |
bytes |
Binary data |
json |
JSON object (stored as string) |
sparse_vector |
Sparse vector for semantic search |
dense_vector |
Dense vector for semantic search |
Example: Python Client
import grpc
from hermes_pb2 import *
from hermes_pb2_grpc import IndexServiceStub, SearchServiceStub
channel = grpc.insecure_channel('localhost:50051')
index_service = IndexServiceStub(channel)
search_service = SearchServiceStub(channel)
# Create index
schema = '''
index articles {
title: text indexed stored
body: text indexed stored
}
'''
index_service.CreateIndex(CreateIndexRequest(
index_name="articles",
schema=schema
))
# Index documents
docs = [
NamedDocument(fields={
"title": FieldValue(text="Hello World"),
"body": FieldValue(text="This is my first article")
}),
NamedDocument(fields={
"title": FieldValue(text="Goodbye World"),
"body": FieldValue(text="This is my last article")
})
]
index_service.BatchIndexDocuments(BatchIndexDocumentsRequest(
index_name="articles",
documents=docs
))
# Commit
index_service.Commit(CommitRequest(index_name="articles"))
# Search
response = search_service.Search(SearchRequest(
index_name="articles",
query=Query(term=TermQuery(field="title", term="hello")),
limit=10,
fields_to_load=["title", "body"]
))
for hit in response.hits:
print(f"Doc {hit.doc_id}: {hit.score} - {hit.fields}")
Docker
Build and run with Docker:
docker build -t hermes-server -f hermes-server/Dockerfile .
docker run -p 50051:50051 -v ./data:/data hermes-server --data-dir /data
Or pull from GitHub Container Registry:
docker pull ghcr.io/spacefrontiers/hermes/hermes-server:latest
docker run -p 50051:50051 -v ./data:/data ghcr.io/spacefrontiers/hermes/hermes-server:latest --data-dir /data
License
MIT
Dependencies
~40–62MB
~811K SLoC