Overview
Taiyo provides two client implementations for interacting with Apache Solr: a synchronous client (SolrClient) and an asynchronous client (AsyncSolrClient). Both share the same API surface with the only difference being that async methods must be awaited.
Client Setup
from taiyo import SolrClient
with SolrClient("http://localhost:8983/solr") as client:
client.set_collection("my_collection")
results = client.search("*:*")
from taiyo import AsyncSolrClient
async with AsyncSolrClient("http://localhost:8983/solr") as client:
client.set_collection("my_collection")
results = await client.search("*:*")
Additional Configurations
from taiyo import SolrClient
client = SolrClient(
base_url="http://localhost:8983/solr",
timeout=30.0, # Request timeout in seconds
verify=True, # SSL certificate verification
)
from taiyo import AsyncSolrClient
client = AsyncSolrClient(
base_url="http://localhost:8983/solr",
timeout=30.0, # Request timeout in seconds
verify=True, # SSL certificate verification
)
SSL Configuration
from taiyo import SolrClient
client = SolrClient(
"https://solr.example.com/solr",
verify=False
)
client = SolrClient(
"https://solr.example.com/solr",
verify="/path/to/ca-bundle.crt"
)
from taiyo import AsyncSolrClient
client = AsyncSolrClient(
"https://solr.example.com/solr",
verify=False
)
client = AsyncSolrClient(
"https://solr.example.com/solr",
verify="/path/to/ca-bundle.crt"
)
httpx Options
Pass any httpx client options:
import httpx
from taiyo import SolrClient
client = SolrClient(
"http://localhost:8983/solr",
timeout=30.0,
limits=httpx.Limits(max_connections=100),
http2=True,
follow_redirects=True,
)
import httpx
from taiyo import AsyncSolrClient
client = AsyncSolrClient(
"http://localhost:8983/solr",
timeout=30.0,
limits=httpx.AsyncLimits(max_connections=100),
http2=True,
follow_redirects=True,
)
Context Managers
Context managers ensure proper resource cleanup:
with SolrClient("http://localhost:8983/solr") as client:
client.set_collection("my_collection")
results = client.search("*:*")
async with AsyncSolrClient("http://localhost:8983/solr") as client:
client.set_collection("my_collection")
results = await client.search("*:*")
Manual Management
Manual cleanup without context managers:
client = SolrClient("http://localhost:8983/solr")
try:
results = client.search("*:*")
finally:
client.close()
from taiyo import AsyncSolrClient
async def main() -> None:
client = AsyncSolrClient("http://localhost:8983/solr")
try:
results = await client.search("*:*")
finally:
await client.close()
Setting the Collection
Most operations require an active collection:
from taiyo import SolrClient
client = SolrClient("http://localhost:8983/solr")
client.set_collection("my_collection")
results = client.search("*:*")
client.add(documents)
client.add_field(field)
from taiyo import AsyncSolrClient
async def main() -> None:
client = AsyncSolrClient("http://localhost:8983/solr")
client.set_collection("my_collection")
results = await client.search("*:*")
await client.add(documents)
await client.add_field(field)
Switching Collections
You can change the active collection at any time:
client.set_collection("collection1")
results1 = client.search("*:*")
client.set_collection("collection2")
results2 = client.search("*:*")
client.set_collection("collection1")
results1 = await client.search("*:*")
client.set_collection("collection2")
results2 = await client.search("*:*")
Core Operations
Ping
Check if Solr is reachable:
if client.ping():
print("Solr is available")
if await client.ping():
print("Solr is available")
Create Collection
Create a new collection:
client.create_collection(
name="my_collection",
num_shards=2,
replication_factor=1,
maxShardsPerNode=2,
collection_configName="myconfig",
)
await client.create_collection(
name="my_collection",
num_shards=2,
replication_factor=1,
maxShardsPerNode=2,
collection_configName="myconfig",
)
Delete Collection
Delete a collection:
client.delete_collection("my_collection")
await client.delete_collection("my_collection")
Document Operations
Adding Documents
Add a single document:
from taiyo import SolrDocument
doc = SolrDocument(
title="Hello World",
content="This is a test document"
)
client.add(doc, commit=True)
from taiyo import AsyncSolrClient, SolrDocument
async def main() -> None:
client = AsyncSolrClient("http://localhost:8983/solr")
doc = SolrDocument(
title="Hello World",
content="This is a test document"
)
await client.add(doc, commit=True)
Add multiple documents:
docs = [
SolrDocument(title="First"),
SolrDocument(title="Second"),
SolrDocument(title="Third")
]
client.add(docs, commit=True)
from taiyo import AsyncSolrClient, SolrDocument
async def main() -> None:
client = AsyncSolrClient("http://localhost:8983/solr")
docs = [
SolrDocument(title="First"),
SolrDocument(title="Second"),
SolrDocument(title="Third")
]
await client.add(docs, commit=True)
Committing Changes
Commit pending changes explicitly:
client.add(doc, commit=False)
client.commit()
await client.add(doc, commit=False)
await client.commit()
Deleting Documents
Delete by ID:
client.delete(ids=["1", "2", "3"], commit=True)
await client.delete(ids=["1", "2", "3"], commit=True)
Delete by query:
client.delete(query="status:archived", commit=True)
await client.delete(query="status:archived", commit=True)
Delete all documents:
client.delete(query="*:*", commit=True)
await client.delete(query="*:*", commit=True)
Searching
Basic Search
# Simple query string
results = client.search("title:test")
# With parameters
results = client.search("*:*", rows=20, start=0)
# Simple query string
results = await client.search("title:test")
# With parameters
results = await client.search("*:*", rows=20, start=0)
Using Query Parsers
from taiyo.parsers import StandardParser
parser = StandardParser(
query="laptop",
query_operator="AND",
default_field="content"
)
results = client.search(parser)
from taiyo.parsers import StandardParser
parser = StandardParser(
query="laptop",
query_operator="AND",
default_field="content"
)
results = await client.search(parser)
With Custom Document Models
from taiyo import SolrDocument
class Product(SolrDocument):
name: str
price: float
category: str
results = client.search("*:*", document_model=Product)
for product in results.docs:
print(f"{product.name}: ${product.price}")
from taiyo import SolrDocument
class Product(SolrDocument):
name: str
price: float
category: str
results = await client.search("*:*", document_model=Product)
for product in results.docs:
print(f"{product.name}: ${product.price}")
Schema Management
Adding Field Types
from taiyo.schema import SolrFieldType, SolrFieldClass
field_type = SolrFieldType(
name="text_custom",
solr_class=SolrFieldClass.TEXT,
position_increment_gap=100
)
client.add_field_type(field_type)
from taiyo.schema import SolrFieldType, SolrFieldClass
field_type = SolrFieldType(
name="text_custom",
solr_class=SolrFieldClass.TEXT,
position_increment_gap=100
)
await client.add_field_type(field_type)
Adding Fields
from taiyo.schema import SolrField
field = SolrField(
name="custom_field",
type="text_general",
indexed=True,
stored=True
)
client.add_field(field)
from taiyo.schema import SolrField
field = SolrField(
name="custom_field",
type="text_general",
indexed=True,
stored=True
)
await client.add_field(field)
Adding Dynamic Fields
from taiyo.schema import SolrDynamicField
dynamic_field = SolrDynamicField(
name="*_txt",
type="text_general",
indexed=True,
stored=True
)
client.add_dynamic_field(dynamic_field)
from taiyo.schema import SolrDynamicField
dynamic_field = SolrDynamicField(
name="*_txt",
type="text_general",
indexed=True,
stored=True
)
await client.add_dynamic_field(dynamic_field)
Error Handling
Handle Solr errors gracefully:
from taiyo import SolrError
try:
results = client.search("invalid:query:[")
except SolrError as e:
print(f"Error: {e}")
print(f"Status: {e.status_code}")
print(f"Response: {e.response}")
from taiyo import SolrError
try:
results = await client.search("invalid:query:[")
except SolrError as e:
print(f"Error: {e}")
print(f"Status: {e.status_code}")
print(f"Response: {e.response}")
Common error scenarios:
try:
client.add(doc)
except SolrError as e:
if e.status_code == 400:
print("Bad request - check document format")
elif e.status_code == 404:
print("Collection not found")
elif e.status_code == 500:
print("Solr server error")
try:
await client.add(doc)
except SolrError as e:
if e.status_code == 400:
print("Bad request - check document format")
elif e.status_code == 404:
print("Collection not found")
elif e.status_code == 500:
print("Solr server error")
Best Practices
Use Context Managers
with SolrClient("http://localhost:8983/solr") as client:
results = client.search("*:*")
async with AsyncSolrClient("http://localhost:8983/solr") as client:
results = await client.search("*:*")
Set Collection Once
client = SolrClient("http://localhost:8983/solr")
client.set_collection("my_collection")
client = AsyncSolrClient("http://localhost:8983/solr")
client.set_collection("my_collection")
Batch Operations
docs = [SolrDocument(title=f"Document {i}") for i in range(1000)]
client.add(docs, commit=True)
docs = [SolrDocument(title=f"Document {i}") for i in range(1000)]
await client.add(docs, commit=True)
Avoid individual operations in loops:
for i in range(1000):
doc = SolrDocument(title=f"Document {i}")
client.add(doc, commit=True)
for i in range(1000):
doc = SolrDocument(title=f"Document {i}")
await client.add(doc, commit=True)
Commit Strategy
For bulk indexing:
for batch in batches:
client.add(batch, commit=False)
client.commit()
for batch in batches:
await client.add(batch, commit=False)
await client.commit()
For real-time updates:
client.add(doc, commit=True)
await client.add(doc, commit=True)
Error Handling
try:
client.create_collection("my_collection")
except SolrError as e:
if "already exists" in str(e).lower():
# Collection exists, that's okay
pass
else:
# Unexpected error
raise
try:
await client.create_collection("my_collection")
except SolrError as e:
if "already exists" in str(e).lower():
# Collection exists, that's okay
pass
else:
# Unexpected error
raise
Performance Tips
Connection Pooling
httpx automatically handles connection pooling. Configure limits:
client = SolrClient(
"http://localhost:8983/solr",
limits=httpx.Limits(
max_keepalive_connections=10,
max_connections=50,
keepalive_expiry=30.0
)
)
client = AsyncSolrClient(
"http://localhost:8983/solr",
limits=httpx.Limits(
max_keepalive_connections=10,
max_connections=50,
keepalive_expiry=30.0
)
)
Timeout Configuration
Configure timeouts based on operation type:
client = SolrClient("http://localhost:8983/solr", timeout=5.0)
client = SolrClient("http://localhost:8983/solr", timeout=300.0)
client = SolrClient("http://localhost:8983/solr", timeout=httpx.Timeout(
connect=5.0,
read=60.0,
write=30.0,
pool=10.0
))
client = AsyncSolrClient("http://localhost:8983/solr", timeout=5.0)
client = AsyncSolrClient("http://localhost:8983/solr", timeout=300.0)
client = AsyncSolrClient("http://localhost:8983/solr", timeout=httpx.Timeout(
connect=5.0,
read=60.0,
write=30.0,
pool=10.0
))
HTTP/2 Support
Enable HTTP/2 for better performance:
client = SolrClient(
"http://localhost:8983/solr",
http2=True
)
client = AsyncSolrClient(
"http://localhost:8983/solr",
http2=True
)
Next Steps
- Learn about Authentication options
- Explore Data Models for type-safe documents
- Master Query Parsers for powerful searches