A Solr client library written in Rust
Reason this release was yanked:
Missing wheels
Project description
Solrstice: A Solr 8+ Client for Rust and Python
Solrstice is a solr client library written in rust. With this wrapper you can use it in python.
Both asyncio and blocking clients are provided. All apis have type hints.
Features
- Config API
- Collection API
- Alias API
- Select Documents
- Grouping Component Query
- Stats Component
- DefTypes (lucene, dismax, edismax)
- Facet Counts (Query, Field, Pivot)
- Json Facet (Query, Stat, Terms, Nested)
- Indexing Documents
- Deleting Documents
Installation
pip install solrstice
Basic Usage
Async
import asyncio
from solrstice import SolrBasicAuth, SolrServerContext, SolrSingleServerHost, AsyncSolrCloudClient, UpdateQuery, \
SelectQuery, DeleteQuery
# A SolrServerContext specifies how the library should interact with Solr
context = SolrServerContext(SolrSingleServerHost('localhost:8983'), SolrBasicAuth('solr', 'SolrRocks'))
client = AsyncSolrCloudClient(context)
async def main() -> None:
# Create config and collection
await client.upload_config('example_config', 'path/to/config')
await client.create_collection('example_collection', 'example_config', shards=1, replication_factor=1)
# Index a document
await client.index(UpdateQuery(), 'example_collection', [{'id': 'example_document', 'title': 'Example document'}])
# Search for the document
response = await client.select(SelectQuery(fq=['title:Example document']), 'example_collection')
docs_response = response.get_docs_response()
assert docs_response is not None
assert docs_response.get_num_found() == 1
docs = docs_response.get_docs()
# Delete the document
await client.delete(DeleteQuery(ids=['example_document']), 'example_collection')
asyncio.run(main())
Blocking
from solrstice import SolrBasicAuth, BlockingSolrCloudClient, SolrServerContext, SolrSingleServerHost, DeleteQuery, \
SelectQuery, UpdateQuery
# A SolrServerContext specifies how the library should interact with Solr
context = SolrServerContext(SolrSingleServerHost('localhost:8983'), SolrBasicAuth('solr', 'SolrRocks'))
client = BlockingSolrCloudClient(context)
# Create config and collection
client.upload_config('example_config', 'path/to/config')
client.create_collection('example_collection', 'example_config', shards=1, replication_factor=1)
# Index a document
client.index(UpdateQuery(), 'example_collection', [{'id': 'example_document', 'title': 'Example document'}])
# Search for the document
response = client.select(SelectQuery(fq=['title:Example document']), 'example_collection')
docs_response = response.get_docs_response()
assert docs_response is not None
assert docs_response.get_num_found() == 1
docs = docs_response.get_docs()
# Delete the document
client.delete(DeleteQuery(ids=['example_document']), 'example_collection')
Grouping component
Field grouping
from solrstice import GroupingComponent, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
group_builder = GroupingComponent(fields=["age"], limit=10)
select_builder = SelectQuery(fq=["age:[* TO *]"], grouping=group_builder)
groups = (await client.select(select_builder, "example_collection")).get_groups()
age_group = groups["age"]
docs = age_group.get_field_result()
Query grouping
from solrstice import GroupingComponent, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
group_builder = GroupingComponent(queries=["age:[0 TO 59]", "age:[60 TO *]"], limit=10)
select_builder = SelectQuery(fq=["age:[* TO *]"], grouping=group_builder)
groups = (await client.select(select_builder, "example_collection")).get_groups()
age_group = groups["age:[0 TO 59]"]
group = age_group.get_query_result()
assert group is not None
docs = group.get_docs()
Query parsers
Lucene
from solrstice import LuceneQuery, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
query_parser = LuceneQuery(df="population")
select_builder = SelectQuery(q="outdoors", def_type=query_parser)
response = (await client.select(select_builder, "example_collection")).get_docs_response()
assert response is not None
docs = response.get_docs()
Dismax
from solrstice import DismaxQuery, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
query_parser = DismaxQuery(qf="interests^20", bq=["interests:cars^20"])
select_builder = SelectQuery(q="outdoors", def_type=query_parser)
response = (await client.select(select_builder, "example_collection")).get_docs_response()
assert response is not None
docs = response.get_docs()
Edismax
from solrstice import EdismaxQuery, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
query_parser = EdismaxQuery(qf="interests^20", bq=["interests:cars^20"])
select_builder = SelectQuery(q="outdoors", def_type=query_parser)
response = (await client.select(select_builder, "example_collection")).get_docs_response()
assert response is not None
docs = response.get_docs()
FacetSet Component
Pivot facet
from solrstice import FacetSetComponent, PivotFacetComponent, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
select_builder = SelectQuery(facet_set=FacetSetComponent(pivots=PivotFacetComponent(["interests,age"])))
response = await client.select(select_builder, "example_collection")
facets = response.get_facet_set()
pivots = facets.get_pivots()
interests_age = pivots.get("interests,age")
Field facet
from solrstice import FacetSetComponent, FieldFacetComponent, FieldFacetEntry, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
facet_set = FacetSetComponent(fields=FieldFacetComponent(fields=[FieldFacetEntry("age")]))
select_builder = SelectQuery(facet_set=facet_set)
response = await client.select(select_builder, "example_collection")
facets = response.get_facet_set()
fields = facets.get_fields()
age = fields.get("age")
Query facet
from solrstice import AsyncSolrCloudClient, SolrServerContext, SelectQuery, FacetSetComponent, FacetSetComponent
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
select_builder = SelectQuery(facet_set=FacetSetComponent(queries=["age:[0 TO 59]"]))
response = await client.select(select_builder, "example_collection")
facets = response.get_facet_set()
queries = facets.get_queries()
query = queries.get("age:[0 TO 59]")
Stats Component
from solrstice import StatsComponent, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
select_builder = SelectQuery(stats=StatsComponent(fields=["age"]))
response = await client.select(select_builder, "example_collection")
stats = response.get_stats()
assert stats is not None
age_stats = stats.get_fields()["age"]
age_count = age_stats.get_count()
Json Facet Component
Query
from solrstice import JsonFacetComponent, JsonQueryFacet, SelectQuery, SolrServerContext, AsyncSolrCloudClient
async def main() -> None:
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
select_builder = SelectQuery(
json_facet=JsonFacetComponent(
facets={"below_60": JsonQueryFacet(q="age:[0 TO 59]")}
)
)
response = await client.select(select_builder, "example_collection")
facets = response.get_json_facets()
assert facets is not None
below_60 = facets.get_nested_facets().get("below_60")
assert below_60 is not None
assert below_60.get_count() == 4
Stat
from solrstice import JsonFacetComponent, JsonStatFacet, SelectQuery, SolrServerContext, AsyncSolrCloudClient
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
select_builder = SelectQuery(
json_facet=JsonFacetComponent(
facets={"total_people": JsonStatFacet("sum(count)")}
)
)
response = await client.select(select_builder, "example_collection")
facets = response.get_json_facets()
assert facets is not None
total_people = facets.get_flat_facets()["total_people"]
assert total_people == 1000
Terms
from solrstice import AsyncSolrCloudClient, SolrServerContext, SelectQuery, JsonFacetComponent, JsonTermsFacet
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
select_builder = SelectQuery(
json_facet=JsonFacetComponent(facets={"age": JsonTermsFacet("age")})
)
response = await client.select(select_builder, "example_collection")
facets = response.get_json_facets()
assert facets is not None
age_buckets = facets.get_nested_facets()["age"].get_buckets()
assert len(age_buckets) == 3
Nested
from solrstice import AsyncSolrCloudClient, SolrServerContext, SelectQuery, JsonFacetComponent, JsonQueryFacet, JsonStatFacet
client = AsyncSolrCloudClient(SolrServerContext('localhost:8983'))
async def main() -> None:
select_builder = SelectQuery(
json_facet=JsonFacetComponent(
facets={
"below_60": JsonQueryFacet(
q="age:[0 TO 59]",
facets={"total_people": JsonStatFacet("sum(count)")},
)
}
)
)
response = await client.select(select_builder, "example_collection")
facets = response.get_json_facets()
assert facets is not None
total_people = (
facets.get_nested_facets()
["below_60"]
.get_flat_facets()
.get("total_people")
)
assert total_people == 750.0
Hosts
Single Server
from solrstice import SolrServerContext, SolrSingleServerHost, SolrBasicAuth, AsyncSolrCloudClient
context = SolrServerContext(SolrSingleServerHost('localhost:8983'), SolrBasicAuth('solr', 'SolrRocks'))
client = AsyncSolrCloudClient(context)
Multiple servers
from solrstice import SolrServerContext, SolrMultipleServerHost, SolrBasicAuth, AsyncSolrCloudClient
# The client will randomly select a server to send requests to. It will wait 5 seconds for a response, before trying another server.
context = SolrServerContext(
SolrMultipleServerHost(["localhost:8983", "localhost:8984"], 5),
SolrBasicAuth('solr', 'SolrRocks'),
)
client = AsyncSolrCloudClient(context)
Zookeeper
from solrstice import SolrServerContext, ZookeeperEnsembleHostConnector, SolrBasicAuth, AsyncSolrCloudClient
async def main() -> None:
context = SolrServerContext(
await ZookeeperEnsembleHostConnector(["localhost:2181"], 30).connect(),
SolrBasicAuth('solr', 'SolrRocks'),
)
client = AsyncSolrCloudClient(context)
Notes
-
Multiprocessing does not work, and will block forever. Normal multithreading works fine.
-
Pyo3, the Rust library for creating bindings does not allow overriding the
__init__method on objects from Rust.__new__has to be overridden instead.For example, if you want to create a simpler way to create a client
from typing import Optional from solrstice import SolrServerContext, SolrSingleServerHost, SolrBasicAuth, AsyncSolrCloudClient, SolrAuth class SolrClient(AsyncSolrCloudClient): def __new__(cls, host: str, auth: Optional[SolrAuth] = None): context = SolrServerContext(SolrSingleServerHost(host), auth) return super().__new__(cls, context=context) client = SolrClient("localhost:8983", SolrBasicAuth("username", "password"))
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file solrstice-0.15.0.tar.gz.
File metadata
- Download URL: solrstice-0.15.0.tar.gz
- Upload date:
- Size: 106.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"25.11","id":"xantusia","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
715f057559c009445b473bf76f37531f4de7366223a6f1fed8e98eebd8815e00
|
|
| MD5 |
87755ba867b9d65fb783a7eca5c26cf1
|
|
| BLAKE2b-256 |
78989e3d34f1eab859855a4b5f46837c127071e35632c7a854cc65f6d7bc5935
|
File details
Details for the file solrstice-0.15.0-cp39-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: solrstice-0.15.0-cp39-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 5.0 MB
- Tags: CPython 3.9+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad7789c673b951772238594d8c1e690798fa1260abfa1383ea19c8a2e8d1f5f9
|
|
| MD5 |
ddd7100ce1be432f26c8592366727dae
|
|
| BLAKE2b-256 |
5e3823234ee7873d01021bc069e6c7f155329a708280a87e023c882c067714bb
|
File details
Details for the file solrstice-0.15.0-cp39-abi3-manylinux_2_28_s390x.whl.
File metadata
- Download URL: solrstice-0.15.0-cp39-abi3-manylinux_2_28_s390x.whl
- Upload date:
- Size: 4.4 MB
- Tags: CPython 3.9+, manylinux: glibc 2.28+ s390x
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
289fb09d0511745b32d5badf1bbcea646248142c5ef0f8305467ef117dec844d
|
|
| MD5 |
a4949a10b59531374c99dba01b59d40e
|
|
| BLAKE2b-256 |
60710eef60072bb66e6996d291639ddcd96597d0cff45d0e4a4399bcad3f7084
|