7.1.1.3. Query Syntax and Execution
7.1.1.3. Query Syntax and Execution
Search queries use simple or full Lucene syntax. Filters, facets, and scoring profiles customize results.
💡 First Principle: Searching unstructured content requires transforming it into searchable form. Azure AI Search has a pipeline for this: Data Source (where content lives) → Indexer (reads and cracks open documents) → Skillset (AI enrichment: OCR, entity extraction, etc.) → Index (searchable structure) → Search (queries). The skillset is the key insight: it's where AI "reads" your documents and extracts searchable fields that didn't exist in the original content.
The following diagram shows the Azure AI Search pipeline. Understanding this flow is critical for exam questions about where to configure enrichment, indexing, and search behaviors.
🔧 Implementation Reference: Azure AI Search
| Item | Value |
|---|---|
| Package | azure-search-documents |
| Classes | SearchClient, SearchIndexClient, SearchIndexerClient |
| Header | api-key |
| Endpoint | POST /indexes/{index}/docs/search |
The three client classes serve different purposes. SearchClient executes queries; SearchIndexClient manages index schemas; SearchIndexerClient manages data ingestion.
Search Client Methods:
| Method | Purpose |
|---|---|
search() | Execute search query |
upload_documents() | Add/update documents |
delete_documents() | Remove documents |
Index field attributes determine how each field can be used in queries. Configure these based on your search requirements.
Index Field Attributes:
| Attribute | Purpose |
|---|---|
searchable | Include in full-text search |
filterable | Enable $filter queries |
sortable | Enable $orderby |
facetable | Enable faceted navigation |
key | Unique identifier (required, one per index) |
Choose the search type based on your query requirements. Hybrid search typically provides the best results by combining multiple approaches.
Search Types:
| Type | Best For |
|---|---|
| Full-text | Keyword matching |
| Semantic | Natural language queries |
| Vector | Conceptual similarity |
| Hybrid | Best overall results |
Hybrid Search Pattern:
from azure.search.documents.models import VectorizedQuery
results = search_client.search(
search_text="query",
vector_queries=[VectorizedQuery(vector=embedding, k_nearest_neighbors=50, fields="contentVector")],
query_type="semantic",
semantic_configuration_name="default"
)
Error Handling Pattern:
from azure.search.documents import SearchClient
from azure.core.exceptions import HttpResponseError, ResourceNotFoundError
def search_with_error_handling(query: str, vector: list = None) -> list:
"""Search with comprehensive error handling."""
try:
search_params = {"search_text": query}
if vector:
search_params["vector_queries"] = [
VectorizedQuery(vector=vector, k_nearest_neighbors=50, fields="contentVector")
]
results = list(search_client.search(**search_params))
return results
except ResourceNotFoundError:
# Index doesn't exist
logging.error("Search index not found. Create index before searching.")
raise
except HttpResponseError as e:
if e.status_code == 400:
# Invalid query syntax or vector dimensions mismatch
if "vector" in str(e).lower():
logging.error("Vector dimensions don't match index field configuration")
else:
logging.error(f"Invalid search query: {e.message}")
elif e.status_code == 403:
# Permission denied - check API key permissions
logging.error("Search API key lacks query permissions")
elif e.status_code == 503:
# Service unavailable - index may be updating
logging.warning("Search service temporarily unavailable")
time.sleep(5)
raise
def upload_documents_with_error_handling(documents: list) -> dict:
"""Upload documents with partial failure handling."""
try:
result = search_client.upload_documents(documents=documents)
# Check for partial failures
failed = [r for r in result if not r.succeeded]
if failed:
for failure in failed:
logging.warning(f"Document {failure.key} failed: {failure.error_message}")
return {
"succeeded": len([r for r in result if r.succeeded]),
"failed": len(failed)
}
except HttpResponseError as e:
logging.error(f"Batch upload failed: {e}")
raise
⚠️ Exam Trap: upload_documents() can return partial success—always check individual document results for failures.
CLI Equivalent (REST):
# Search query
curl -X POST "https://{service}.search.windows.net/indexes/{index}/docs/search?api-version=2024-07-01" \
-H "Content-Type: application/json" \
-H "api-key: {key}" \
-d '{"search": "query text", "queryType": "semantic", "semanticConfiguration": "default"}'
# Upload documents
curl -X POST "https://{service}.search.windows.net/indexes/{index}/docs/index?api-version=2024-07-01" \
-H "Content-Type: application/json" \
-H "api-key: {key}" \
-d '{"value": [{"@search.action": "upload", "id": "1", "content": "Document text"}]}'
# Create/update index
curl -X PUT "https://{service}.search.windows.net/indexes/{index}?api-version=2024-07-01" \
-H "Content-Type: application/json" \
-H "api-key: {admin-key}" \
-d '{"name": "index", "fields": [{"name": "id", "type": "Edm.String", "key": true}]}'