基于Django+Haystack实现用户输入时的搜索建议咨询
Got it, let's tackle adding search suggestions for your MainData model with your specific tech stack. I'll walk you through each step clearly, since you're using Django 1.11.8, Haystack 2.7.0, Solr 6.6.3, and Python 3.
First, we need to set up Solr's suggestion (spellcheck) component, since that's where the heavy lifting for autocomplete happens.
Update Solr's Managed Schema
Open your Solr core's managed-schema file (usually in solr/your_core/conf/) and add these configurations:
<!-- Field type optimized for suggestions (handles partial matches) --> <fieldType name="text_suggest" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="20"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType> <!-- Dedicated field to store suggestion data --> <field name="suggest" type="text_suggest" indexed="true" stored="false" multiValued="true"/> <!-- Copy your MainData's title field into the suggest field --> <copyField source="title" dest="suggest"/>
Configure Solr's Request Handler and Spellcheck Component
Next, edit solrconfig.xml in the same conf folder to add the suggestion endpoint:
<!-- Request handler to serve suggestions --> <requestHandler name="/suggest" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str> <str name="df">suggest</str> <str name="spellcheck">true</str> <str name="spellcheck.dictionary">suggestDict</str> <str name="spellcheck.onlyMorePopular">true</str> <str name="spellcheck.count">10</str> <str name="spellcheck.collate">false</str> </lst> <arr name="components"> <str>spellcheck</str> </arr> </requestHandler> <!-- Spellcheck dictionary tied to our suggest field --> <searchComponent name="spellcheck" class="solr.SpellCheckComponent"> <lst name="spellchecker"> <str name="name">suggestDict</str> <str name="classname">org.apache.solr.spelling.suggest.Suggester</str> <str name="lookupImpl">org.apache.solr.spelling.suggest.tst.TSTLookup</str> <str name="field">suggest</str> <float name="threshold">0.001</float> <str name="buildOnCommit">true</str> </lst> </searchComponent>
Restart Solr after making these changes—this ensures the new configurations take effect.
Make sure your Haystack index is properly configured to index the title field, which we'll use for suggestions.
Create the Search Index
In your app's search_indexes.py file (create it if it doesn't exist):
from haystack import indexes from .models import MainData class MainDataIndex(indexes.SearchIndex, indexes.Indexable): # Primary document field (required by Haystack) text = indexes.CharField(document=True, use_template=True) # Index the title field explicitly title = indexes.CharField(model_attr='title') def get_model(self): return MainData def index_queryset(self, using=None): # Exclude entries with empty titles to avoid useless suggestions return self.get_model().objects.exclude(title__isnull=True).exclude(title__exact='')
Create the Index Template
Create a template at templates/search/indexes/your_app_name/maindata_text.txt (replace your_app_name with your actual app name):
{{ object.title }}
Rebuild the Index
Run this command to reindex all your MainData entries so the new suggest field gets populated:
python manage.py rebuild_index
Haystack 2.7.0 doesn't have out-of-the-box support for Solr suggestions, so we'll use pysolr directly to query Solr's /suggest endpoint.
Add the View
In your app's views.py:
import json import pysolr from django.http import JsonResponse from django.conf import settings def search_suggestions(request): query = request.GET.get('q', '').strip() if not query: return JsonResponse({'suggestions': []}) # Initialize connection to Solr using your Haystack config solr_client = pysolr.Solr( settings.HAYSTACK_CONNECTIONS['default']['URL'], timeout=10 ) # Fetch suggestions from Solr solr_response = solr_client.search( '', spellcheck_q=query, qt='/suggest' ) # Parse suggestions from the raw Solr response suggestions = [] spellcheck_data = solr_response.raw_response.get('spellcheck', {}) if 'suggestions' in spellcheck_data: for item in spellcheck_data['suggestions']: if isinstance(item, dict) and 'suggestion' in item: suggestions.extend(item['suggestion']) # Remove duplicates and limit to 10 results unique_suggestions = list(set(suggestions))[:10] return JsonResponse({'suggestions': unique_suggestions})
Add a URL Route
Update your app's urls.py to map the view to a URL:
from django.conf.urls import url from . import views urlpatterns = [ # ... your existing URLs url(r'^search-suggestions/$', views.search_suggestions, name='search_suggestions'), ]
Finally, add a search input and JavaScript to fetch and display suggestions as the user types.
Template Code
Add this to your search template:
<div class="search-container"> <input type="text" id="search-input" placeholder="Search titles..."> <ul id="suggestions-list"></ul> </div> <script> const searchInput = document.getElementById('search-input'); const suggestionsList = document.getElementById('suggestions-list'); // Fetch suggestions on input searchInput.addEventListener('input', function() { const query = this.value.trim(); if (!query) { suggestionsList.innerHTML = ''; return; } fetch(`{% url 'search_suggestions' %}?q=${encodeURIComponent(query)}`) .then(response => response.json()) .then(data => { suggestionsList.innerHTML = ''; data.suggestions.forEach(suggestion => { const li = document.createElement('li'); li.textContent = suggestion; // Fill input when suggestion is clicked li.addEventListener('click', () => { searchInput.value = suggestion; suggestionsList.innerHTML = ''; // Optional: Submit your search form here }); suggestionsList.appendChild(li); }); }) .catch(err => console.error('Failed to load suggestions:', err)); }); // Hide suggestions when clicking outside document.addEventListener('click', (e) => { if (!searchInput.contains(e.target) && !suggestionsList.contains(e.target)) { suggestionsList.innerHTML = ''; } }); </script>
- Performance: If you have a huge dataset,
buildOnCommitin Solr might slow down writes. You can switch to manually building the suggestion dictionary by callinghttp://localhost:8983/solr/your_core/suggest?spellcheck.build=true. - Filtering: Adjust the
index_querysetin your Haystack index to include/exclude entries as needed. - Styling: Add CSS to the suggestions list to make it look like a proper autocomplete dropdown.
内容的提问来源于stack exchange,提问作者Dhaval Savalia

