Files
thrillwiki_django_no_react/memory-bank/features/search_improvements.md

3.2 KiB

Search Functionality Improvement Plan

Technical Implementation Details

1. Database Optimization

# 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

# 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

// 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
uv run manage.py makemigrations parks --name add_search_indexes
uv run manage.py migrate
  1. Service Layer Integration
  • Create search/services.py with query instrumentation
  • Update all views to use SearchEngine class
  1. Frontend Updates
  • Add debouncing to search inputs
  • Implement error handling UI components
  • Add loading spinner component
  1. Monitoring Setup
# 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)
  1. Performance Testing
  • Use django-debug-toolbar for query analysis
  • Generate load tests with locust.io