nlp4j-local-search-embedding
nlp4j-local-search-embedding provides simple embedding-based semantic search built on top of nlp4j-local-search.
It converts text into embeddings using a multilingual E5 model and stores the resulting vectors in a local vector search index.
Features
- Simple semantic search API
- Text-to-vector embedding with multilingual E5
- Local vector search using
nlp4j-local-search - E5 query/passage prefixes handled internally
- Supports document IDs, text, and metadata
- Field search — filter search results by document fields (added in v0.3.0)
- Designed as a lightweight bridge between local search and embedding models
Installation
nlp4j-local-search-embedding is available on PyPI.
Install the latest version with:
pip install nlp4j-local-search-embedding==0.3.0
This package depends on nlp4j-local-search and sentence-transformers.
The first run may take some time because the embedding model is downloaded and loaded locally.
Local Development Installation
For local development with editable installs:
git clone https://github.com/oyahiroki/nlp4j-local-search.git
git clone https://github.com/oyahiroki/nlp4j-local-search-embedding.git
python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip setuptools wheel
python -m pip install -e ./nlp4j-local-search
python -m pip install -e ./nlp4j-local-search-embedding
On Windows PowerShell:
git clone https://github.com/oyahiroki/nlp4j-local-search.git
git clone https://github.com/oyahiroki/nlp4j-local-search-embedding.git
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -U pip setuptools wheel
python -m pip install -e ./nlp4j-local-search
python -m pip install -e ./nlp4j-local-search-embedding
Quick Start
from nlp4j_local_search_embedding import SemanticSearch
app = SemanticSearch("en")
app.add({
"doc1": "Kyoto is a historic city in Japan.",
"doc2": "Tokyo is the capital city of Japan.",
"doc3": "Python is a popular programming language.",
})
app.commit()
results = app.search("an old Japanese capital", limit=10)
print("=== Search results ===")
print(f"number of results: {len(results)}")
for i, result in enumerate(results):
print(f"result[{i}].id: {result.id}")
print(f"result[{i}].text: {result.text}")
print(f"result[{i}].score: {result.score}")
print(f"result[{i}].metadata: {result.metadata}")
print("---")
Example output:
=== Search results ===
number of results: 3
result[0].id: doc1
result[0].text: Kyoto is a historic city in Japan.
result[0].score: 0.91
result[0].metadata: {}
---
result[1].id: doc2
result[1].text: Tokyo is the capital city of Japan.
result[1].score: 0.88
result[1].metadata: {}
---
result[2].id: doc3
result[2].text: Python is a popular programming language.
result[2].score: 0.75
result[2].metadata: {}
---
Scores may vary depending on the model version and runtime environment.
Using Metadata
Documents can include metadata.
from nlp4j_local_search_embedding import SemanticSearch
documents = [
{
"id": "doc1",
"text": "Kyoto is a historic city in Japan.",
"metadata": {
"category": "city",
"country": "Japan"
},
},
{
"id": "doc2",
"text": "Nintendo is a video game company headquartered in Kyoto.",
"metadata": {
"category": "company",
"country": "Japan"
},
},
{
"id": "doc3",
"text": "Python is widely used for data science and machine learning.",
"metadata": {
"category": "technology"
},
},
]
app = SemanticSearch("en")
app.add(documents)
app.commit()
results = app.search("a Japanese game company", limit=3)
for result in results:
print(result.id)
print(result.text)
print(result.score)
print(result.metadata)
print("---")
Adding a Single Document
from nlp4j_local_search_embedding import SemanticSearch
app = SemanticSearch("en")
app.add(
"doc1",
"Kyoto is known for temples, shrines, and traditional culture.",
metadata={"category": "travel"}
)
app.commit()
results = app.search("traditional Japanese culture", limit=5)
for result in results:
print(result.id, result.score, result.text)
Field Search
Added in v0.3.0.
Documents can be registered with fields — key-value pairs used for exact-match filtering.
Use fields= when adding documents and filters= when searching.
filters conditions are combined with AND when multiple fields are specified.
Field values are evaluated by exact (term) match and do not affect the similarity score.
Registering documents with fields
from nlp4j_local_search_embedding import SemanticSearch
app = SemanticSearch("en")
app.add([
{"id": "1", "text": "Kyoto is a historic city in Japan.",
"fields": {"category": "city", "country": "Japan"}},
{"id": "2", "text": "Nintendo is headquartered in Kyoto, Japan.",
"fields": {"category": "company", "country": "Japan"}},
{"id": "3", "text": "Tokyo is the capital city of Japan.",
"fields": {"category": "city", "country": "Japan"}},
{"id": "4", "text": "Paris is the capital city of France.",
"fields": {"category": "city", "country": "France"}},
{"id": "5", "text": "Sony is a Japanese multinational company.",
"fields": {"category": "company", "country": "Japan"}},
])
app.commit()
Filtering by a single field
results = app.search("", limit=10, filters={"category": "city"})
for r in results:
print(r.id, r.text)
# [1] Kyoto is a historic city in Japan.
# [3] Tokyo is the capital city of Japan.
# [4] Paris is the capital city of France.
Filtering by multiple fields (AND)
results = app.search("", limit=10, filters={"category": "city", "country": "Japan"})
for r in results:
print(r.id, r.text)
# [1] Kyoto is a historic city in Japan.
# [3] Tokyo is the capital city of Japan.
Semantic search combined with field filtering
results = app.search("Japanese company", limit=10, filters={"category": "company"})
for r in results:
print(r.id, r.score, r.text)
# Only documents with category="company" are returned, ranked by semantic similarity.
Two-argument form with fields
app.add("doc1", "Kyoto is a historic city in Japan.",
fields={"category": "city", "country": "Japan"})
Using the Document class with fields
from nlp4j_local_search_embedding import Document, SemanticSearch
app = SemanticSearch("en")
app.add([
Document(id="1", text="Kyoto is a historic city in Japan.",
fields={"category": "city", "country": "Japan"}),
Document(id="2", text="Nintendo is headquartered in Kyoto, Japan.",
fields={"category": "company", "country": "Japan"}),
])
app.commit()
results = app.search("old capital", limit=5, filters={"category": "city"})
Default Model
The default embedding model is:
intfloat/multilingual-e5-large
SemanticSearch uses the E5-style prefixes internally:
passage: <document text>
query: <search query>
Therefore, users can simply add plain document text and search with plain query text.
Specifying a Model
from nlp4j_local_search_embedding import SemanticSearch
app = SemanticSearch(
"en",
model_name="intfloat/multilingual-e5-large"
)
Architecture
This package is designed as an embedding layer for nlp4j-local-search.
text documents
|
v
E5 embedding model
|
v
vectors
|
v
nlp4j-local-search vector index
|
v
semantic search results
The base package nlp4j-local-search is responsible for local search and vector indexing.
This package is responsible for converting text into embeddings and providing a convenient SemanticSearch API.
Relationship with nlp4j-local-search
nlp4j-local-search can perform keyword search and vector search with user-provided vectors.
from nlp4j_local_search import SearchEngine
search = SearchEngine("en", vector_dimension=2)
search.add("east", [1.0, 0.0])
search.add("north", [0.0, 1.0])
search.commit()
results = search.search([0.9, 0.1], limit=10)
nlp4j-local-search-embedding adds text embedding support on top of that.
from nlp4j_local_search_embedding import SemanticSearch
search = SemanticSearch("en")
search.add({
"doc1": "Kyoto is a historic city in Japan.",
"doc2": "Tokyo is the capital city of Japan.",
})
search.commit()
results = search.search("old Japanese capital", limit=10)
Saving Document Text and Metadata
The vector index is managed by nlp4j-local-search.
This package also keeps document text and metadata on the Python side so that search results can include the original text.
app.save_documents("documents.json")
To restore the document text and metadata:
app.load_documents("documents.json")
Note: index persistence and document-store persistence may be handled separately depending on the version of nlp4j-local-search.
Development
Install the package in editable mode:
python -m pip install -e .
Run an example:
python examples/simple_semantic_search.py
Run tests:
python -m pip install pytest
python -m pytest
Project Structure
nlp4j-local-search-embedding/
src/
nlp4j_local_search_embedding/
__init__.py
document.py
e5_embedder.py
errors.py
result.py
semantic_search.py
examples/
simple_semantic_search.py
example_0.3.0.py
tests/
pyproject.toml
README.md
README_build.md
LICENSE
Notes
- The first run may take time because the embedding model needs to be downloaded and loaded.
- The package depends on
sentence-transformers. - The base vector search functionality is provided by
nlp4j-local-search. - This package is intended for local semantic search, experimentation, and lightweight RAG-style applications.
License
Apache License 2.0
Metadata
Release files for nlp4j-local-search-embedding 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nlp4j_local_search_embedding-0.3.0.tar.gz | 19.6 kB | Without provenance | Details for nlp4j_local_search_embedding-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nlp4j_local_search_embedding-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for nlp4j_local_search_embedding-0.3.0-py3-none-any.whl |
Total release size: 33.0 kB
Release files / nlp4j_local_search_embedding-0.3.0.tar.gz
| Download URL | nlp4j_local_search_embedding-0.3.0.tar.gz |
|---|---|
| Size | 19.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6b88f9cc64219ef7a57056f89f502a0cf8973b611f55e47cc1b13ac122f886ad
|
|
BLAKE2b-256 checksum How to use checksums |
5aafcb76174e1b393ee63fe2660f187078ae9d8435bec9cdee2d37466395f8e4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Release files / nlp4j_local_search_embedding-0.3.0-py3-none-any.whl
| Download URL | nlp4j_local_search_embedding-0.3.0-py3-none-any.whl |
|---|---|
| Size | 13.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
14b377ad8eac7b9ba8c5f985dfe104d4e36f97875984fa9c3663997ef111c7f8
|
|
BLAKE2b-256 checksum How to use checksums |
caffa2dead1b52baa357b54f4e6e8b6c85841c85d77ee4c534c2340361c98fcf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.10.12
|
Security for nlp4j-local-search-embedding 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.