Implement search functionality improvements: optimize database queries, enhance service layer, and update frontend interactions

This commit is contained in:
pacnpal
2025-02-21 10:31:49 -05:00
parent 8c85b2afd4
commit 645a74a4c3
4 changed files with 262 additions and 78 deletions

View File

@@ -0,0 +1,119 @@
# Search Functionality Improvement Plan
## Technical Implementation Details
### 1. Database Optimization
```python
# parks/models.py
from django.contrib.postgres.indexes import GinIndex
class Park(models.Model):
class Meta:
indexes = [
GinIndex(fields=['name', 'description'],
name='search_gin_idx',
opclasses=['gin_trgm_ops', 'gin_trgm_ops']),
Index(fields=['location__address_text'], name='location_addr_idx')
]
# search/services.py
from django.db.models import F, Func
from analytics.models import SearchMetric
class SearchEngine:
@classmethod
def execute_search(cls, request, filterset_class):
with timeit() as timer:
filterset = filterset_class(request.GET, queryset=cls.base_queryset())
qs = filterset.qs
results = qs.annotate(
search_rank=Func(F('name'), F('description'),
function='ts_rank')
).order_by('-search_rank')
SearchMetric.record(
query_params=dict(request.GET),
result_count=qs.count(),
duration=timer.elapsed
)
return results
```
### 2. Architectural Changes
```python
# search/filters.py (simplified explicit filter)
class ParkFilter(SearchableFilterMixin, django_filters.FilterSet):
search_fields = ['name', 'description', 'location__address_text']
class Meta:
model = Park
fields = {
'ride_count': ['gte', 'lte'],
'coaster_count': ['gte', 'lte'],
'average_rating': ['gte', 'lte']
}
# search/views.py (updated)
class AdaptiveSearchView(TemplateView):
def get_queryset(self):
return SearchEngine.base_queryset()
def get_filterset(self):
return ParkFilter(self.request.GET, queryset=self.get_queryset())
```
### 3. Frontend Enhancements
```javascript
// static/js/search.js
const searchInput = document.getElementById('search-input');
let timeoutId;
searchInput.addEventListener('input', () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fetchResults(searchInput.value);
}, 300);
});
async function fetchResults(query) {
try {
const response = await fetch(`/search/?search=${encodeURIComponent(query)}`);
if (!response.ok) throw new Error(response.statusText);
const html = await response.text();
updateResults(html);
} catch (error) {
showError(`Search failed: ${error.message}`);
}
}
```
## Implementation Roadmap
1. Database Migrations
```bash
uv run manage.py makemigrations parks --name add_search_indexes
uv run manage.py migrate
```
2. Service Layer Integration
- Create search/services.py with query instrumentation
- Update all views to use SearchEngine class
3. Frontend Updates
- Add debouncing to search inputs
- Implement error handling UI components
- Add loading spinner component
4. Monitoring Setup
```python
# analytics/models.py
class SearchMetric(models.Model):
query_params = models.JSONField()
result_count = models.IntegerField()
duration = models.FloatField()
created_at = models.DateTimeField(auto_now_add=True)
```
5. Performance Testing
- Use django-debug-toolbar for query analysis
- Generate load tests with locust.io