Module 2: Practice and Implementation¶
Overview¶
Now that you understand the concepts of Azure AI Search basic operations, it's time to put your knowledge into practice with real code examples and hands-on exercises.
🎯 Ready to Code?¶
Now that you understand the concepts, it's time to practice with real code:
1. 📓 Start with Interactive Learning¶
- Open the Jupyter Notebook for guided, step-by-step examples
- Run each cell and experiment with different queries
- Modify examples to test your understanding
2. 🐍 Explore Complete Examples¶
- Run
basic_search.pyto see all search operations in action - Study
search_variations.pyfor different query patterns - Experiment with different search parameters and observe the results
3. 🛡️ Learn Production Patterns¶
- Review
error_handling.pyfor robust error handling - Explore
advanced_patterns.pyfor sophisticated search strategies - Understand how to implement fallback mechanisms and retry logic
4. 📊 Master Result Processing¶
- Use
result_processing.pyfor formatting and analysis - Learn to export results in multiple formats
- Practice with pagination and result filtering
📚 Complete Code Samples Guide¶
Visit the code samples documentation for:
- Detailed explanations of each file and its purpose
- Usage examples and code snippets you can copy and modify
- Configuration instructions for different environments
- Troubleshooting guides for common issues
- Performance tips and optimization techniques
🎯 Learning Paths¶
Beginner Path (Recommended)¶
- Theory First: Complete reading the main documentation
- Setup: Ensure prerequisites are completed
- Interactive: Start with the Jupyter notebook for guided learning
- Practice: Work through Python examples sequentially
- Experiment: Modify examples with your own queries and data
Hands-On Path¶
- Jump In: Start directly with code examples
- Learn by Doing: Run examples and observe outputs
- Reference: Use documentation to understand concepts as needed
- Customize: Adapt examples to your specific use cases
Production Path¶
- Best Practices: Review best practices guide
- Error Handling: Study robust error handling patterns
- Performance: Learn optimization techniques
- Integration: Implement in your own applications
🔧 Practical Exercises¶
Exercise 1: Basic Search Mastery¶
Objective: Master all 5 basic search types
Tasks:
- Perform simple text searches with different keywords
- Practice phrase searches with exact matches
- Build complex boolean queries using AND, OR, NOT
- Use wildcards to find term variations
- Target specific fields for precise results
Success Criteria:
- [ ] Can execute all 5 search types successfully
- [ ] Understands when to use each search type
- [ ] Can combine different search techniques
Exercise 2: Result Processing¶
Objective: Learn to handle and format search results effectively
Tasks:
- Extract key information from search results
- Format results for different display contexts
- Implement pagination for large result sets
- Sort results by different criteria (score, date, etc.)
- Create result summaries and statistics
Success Criteria:
- [ ] Can process results programmatically
- [ ] Understands search scores and relevance
- [ ] Can implement pagination correctly
Exercise 3: Error Handling¶
Objective: Build robust search applications
Tasks:
- Handle connection errors gracefully
- Validate user input before searching
- Implement fallback strategies for failed searches
- Log errors appropriately for debugging
- Provide user-friendly error messages
Success Criteria:
- [ ] Application doesn't crash on errors
- [ ] Users receive helpful error messages
- [ ] Errors are logged for troubleshooting
Exercise 4: Performance Optimization¶
Objective: Create efficient search implementations
Tasks:
- Limit result sets to necessary sizes
- Select only required fields in results
- Implement result caching where appropriate
- Use field-specific searches for better performance
- Monitor and measure search performance
Success Criteria:
- [ ] Searches complete in reasonable time
- [ ] Network traffic is minimized
- [ ] Application scales with usage
🚀 Implementation Patterns¶
Pattern 1: Simple Search Interface¶
def simple_search_interface():
"""Basic search interface for user queries"""
while True:
query = input("Enter search query (or 'quit' to exit): ")
if query.lower() == 'quit':
break
try:
results = search_client.search(query, top=5)
print(f"\nFound results for '{query}':")
for i, result in enumerate(results, 1):
print(f"{i}. {result.get('title', 'No title')}")
print(f" Score: {result['@search.score']:.3f}")
print(f" Author: {result.get('author', 'Unknown')}")
print()
except Exception as e:
print(f"Search failed: {e}")
Pattern 2: Advanced Search with Filters¶
def advanced_search(query, filters=None, sort_by=None):
"""Advanced search with filtering and sorting"""
search_params = {
'search_text': query,
'top': 20,
'include_total_count': True
}
if filters:
search_params['filter'] = filters
if sort_by:
search_params['order_by'] = sort_by
try:
results = search_client.search(**search_params)
return {
'results': list(results),
'total_count': results.get_count(),
'success': True
}
except Exception as e:
return {
'results': [],
'total_count': 0,
'success': False,
'error': str(e)
}
Pattern 3: Search with Analytics¶
import time
from collections import defaultdict
class SearchAnalytics:
def __init__(self):
self.search_stats = defaultdict(int)
self.performance_stats = []
def tracked_search(self, query):
"""Search with performance tracking"""
start_time = time.time()
try:
results = list(search_client.search(query, top=10))
execution_time = time.time() - start_time
# Track statistics
self.search_stats['total_searches'] += 1
self.search_stats['successful_searches'] += 1
self.performance_stats.append(execution_time)
return {
'results': results,
'execution_time': execution_time,
'result_count': len(results)
}
except Exception as e:
self.search_stats['failed_searches'] += 1
return {
'results': [],
'execution_time': time.time() - start_time,
'error': str(e)
}
def get_stats(self):
"""Get search analytics"""
avg_time = sum(self.performance_stats) / len(self.performance_stats) if self.performance_stats else 0
return {
'total_searches': self.search_stats['total_searches'],
'success_rate': self.search_stats['successful_searches'] / max(1, self.search_stats['total_searches']),
'average_response_time': avg_time,
'fastest_search': min(self.performance_stats) if self.performance_stats else 0,
'slowest_search': max(self.performance_stats) if self.performance_stats else 0
}
🔍 Testing Your Implementation¶
Unit Testing Example¶
import unittest
from unittest.mock import Mock, patch
class TestSearchFunctionality(unittest.TestCase):
def setUp(self):
self.mock_client = Mock()
def test_simple_search(self):
"""Test basic search functionality"""
# Mock search results
mock_results = [
{'title': 'Test Document', '@search.score': 1.5},
{'title': 'Another Document', '@search.score': 1.2}
]
self.mock_client.search.return_value = mock_results
# Test search
results = list(self.mock_client.search("test query"))
# Assertions
self.assertEqual(len(results), 2)
self.assertEqual(results[0]['title'], 'Test Document')
self.mock_client.search.assert_called_once_with("test query")
def test_error_handling(self):
"""Test error handling in search"""
# Mock search exception
self.mock_client.search.side_effect = Exception("Connection failed")
# Test error handling
try:
results = list(self.mock_client.search("test query"))
self.fail("Expected exception was not raised")
except Exception as e:
self.assertEqual(str(e), "Connection failed")
if __name__ == '__main__':
unittest.main()
Integration Testing¶
def integration_test():
"""Test complete search workflow"""
print("Running integration tests...")
# Test 1: Basic connectivity
try:
count = search_client.get_document_count()
print(f"✅ Connection test passed - {count} documents in index")
except Exception as e:
print(f"❌ Connection test failed: {e}")
return False
# Test 2: Simple search
try:
results = list(search_client.search("test", top=1))
print(f"✅ Simple search test passed - {len(results)} results")
except Exception as e:
print(f"❌ Simple search test failed: {e}")
return False
# Test 3: Complex search
try:
results = list(search_client.search("python AND tutorial", top=5))
print(f"✅ Complex search test passed - {len(results)} results")
except Exception as e:
print(f"❌ Complex search test failed: {e}")
return False
print("🎉 All integration tests passed!")
return True
📈 Performance Monitoring¶
Search Performance Metrics¶
class SearchPerformanceMonitor:
def __init__(self):
self.metrics = {
'total_searches': 0,
'total_time': 0,
'slow_searches': 0,
'failed_searches': 0
}
def monitor_search(self, query, threshold_ms=1000):
"""Monitor search performance"""
start_time = time.time()
try:
results = list(search_client.search(query))
execution_time = (time.time() - start_time) * 1000 # Convert to ms
# Update metrics
self.metrics['total_searches'] += 1
self.metrics['total_time'] += execution_time
if execution_time > threshold_ms:
self.metrics['slow_searches'] += 1
print(f"⚠️ Slow search detected: {execution_time:.2f}ms for '{query}'")
return results
except Exception as e:
self.metrics['failed_searches'] += 1
print(f"❌ Search failed: {e}")
return []
def get_performance_report(self):
"""Generate performance report"""
if self.metrics['total_searches'] == 0:
return "No searches performed yet"
avg_time = self.metrics['total_time'] / self.metrics['total_searches']
success_rate = ((self.metrics['total_searches'] - self.metrics['failed_searches']) /
self.metrics['total_searches']) * 100
return f"""
Performance Report:
- Total searches: {self.metrics['total_searches']}
- Average response time: {avg_time:.2f}ms
- Success rate: {success_rate:.1f}%
- Slow searches: {self.metrics['slow_searches']}
- Failed searches: {self.metrics['failed_searches']}
"""
🎓 Next Steps After Practice¶
Once you've completed the practice exercises:
- 📖 Review Best Practices - Learn professional implementation techniques
- 🛠️ Study Troubleshooting - Prepare for common issues
- 🎯 Move to Module 3 - Learn index management
- 🔧 Build Your Own Project - Apply concepts to real applications
📋 Practice Completion Checklist¶
You've mastered basic search operations when you can:
- [ ] Execute all search types - Simple, phrase, boolean, wildcard, field-specific
- [ ] Handle results effectively - Process, format, and paginate results
- [ ] Implement error handling - Graceful error recovery and user feedback
- [ ] Optimize performance - Efficient queries and result processing
- [ ] Test your code - Unit tests and integration tests
- [ ] Monitor performance - Track and analyze search metrics
- [ ] Adapt to your needs - Customize examples for your use cases
Ready to build something amazing? You now have the foundation to create powerful search applications with Azure AI Search! 🚀