Merge pull request #348 from kaedroho/searchchanges/bits-and-pieces

Search Changes 7 - Some small changes
This commit is contained in:
Matt Westcott 2014-07-07 19:33:53 +01:00
commit be31e8bf0b
6 changed files with 58 additions and 64 deletions

View file

@ -6,10 +6,6 @@ from wagtail.wagtaildocs import urls as wagtaildocs_urls
from wagtail.wagtailsearch.urls import frontend as wagtailsearch_frontend_urls
from wagtail.contrib.wagtailsitemaps.views import sitemap
# Signal handlers
from wagtail.wagtailsearch import register_signal_handlers as wagtailsearch_register_signal_handlers
wagtailsearch_register_signal_handlers()
urlpatterns = patterns('',
url(r'^admin/', include(wagtailadmin_urls)),

View file

@ -22,7 +22,7 @@ class DBSearch(BaseSearch):
pass # Not needed
def add_bulk(self, obj_list):
pass # Not needed
return [] # Not needed
def delete(self, obj):
pass # Not needed
@ -49,7 +49,7 @@ class DBSearch(BaseSearch):
# Filter by terms
for term in terms:
term_query = None
term_query = models.Q()
for field_name in fields:
# Check if the field exists (this will filter out indexed callables)
try:
@ -58,11 +58,8 @@ class DBSearch(BaseSearch):
continue
# Filter on this field
field_filter = {'%s__icontains' % field_name: term}
if term_query is None:
term_query = models.Q(**field_filter)
else:
term_query |= models.Q(**field_filter)
term_query |= models.Q(**{'%s__icontains' % field_name: term})
query = query.filter(term_query)
# Distinct
@ -73,4 +70,4 @@ class DBSearch(BaseSearch):
for prefetch in prefetch_related:
query = query.prefetch_related(prefetch)
return query
return query

View file

@ -41,7 +41,7 @@ class ElasticSearchMapping(object):
# Make field list
fields = {
'pk': dict(type='string', index='not_analyzed', store='yes'),
'content_type': dict(type='string'),
'content_type': dict(type='string', index='not_analyzed'),
}
fields.update(dict(
@ -65,7 +65,7 @@ class ElasticSearchMapping(object):
doc[field] = getattr(obj, field)
# Check if this field is callable
if hasattr(doc[field], "__call__"):
if hasattr(doc[field], '__call__'):
# Call it
doc[field] = doc[field]()
@ -346,43 +346,43 @@ class ElasticSearch(BaseSearch):
# Settings
INDEX_SETTINGS = {
"settings": {
"analysis": {
"analyzer": {
"ngram_analyzer": {
"type": "custom",
"tokenizer": "lowercase",
"filter": ["ngram"]
'settings': {
'analysis': {
'analyzer': {
'ngram_analyzer': {
'type': 'custom',
'tokenizer': 'lowercase',
'filter': ['ngram']
},
"edgengram_analyzer": {
"type": "custom",
"tokenizer": "lowercase",
"filter": ["edgengram"]
'edgengram_analyzer': {
'type': 'custom',
'tokenizer': 'lowercase',
'filter': ['edgengram']
}
},
"tokenizer": {
"ngram_tokenizer": {
"type": "nGram",
"min_gram": 3,
"max_gram": 15,
'tokenizer': {
'ngram_tokenizer': {
'type': 'nGram',
'min_gram': 3,
'max_gram': 15,
},
"edgengram_tokenizer": {
"type": "edgeNGram",
"min_gram": 2,
"max_gram": 15,
"side": "front"
'edgengram_tokenizer': {
'type': 'edgeNGram',
'min_gram': 2,
'max_gram': 15,
'side': 'front'
}
},
"filter": {
"ngram": {
"type": "nGram",
"min_gram": 3,
"max_gram": 15
'filter': {
'ngram': {
'type': 'nGram',
'min_gram': 3,
'max_gram': 15
},
"edgengram": {
"type": "edgeNGram",
"min_gram": 1,
"max_gram": 15
'edgengram': {
'type': 'edgeNGram',
'min_gram': 1,
'max_gram': 15
}
}
}
@ -447,6 +447,7 @@ class ElasticSearch(BaseSearch):
action.update(doc)
actions.append(action)
yield type_name, len(type_documents)
bulk(self.es, actions)
def delete(self, obj):

View file

@ -15,13 +15,13 @@ class Indexed(object):
@classmethod
def indexed_get_content_type(cls):
# Work out content type
content_type = (cls._meta.app_label + "_" + cls.__name__).lower()
content_type = (cls._meta.app_label + '_' + cls.__name__).lower()
# Get parent content type
parent = cls.indexed_get_parent()
if parent:
parent_content_type = parent.indexed_get_content_type()
return parent_content_type + "_" + content_type
return parent_content_type + '_' + content_type
else:
return content_type
@ -33,7 +33,7 @@ class Indexed(object):
return parent.indexed_get_content_type()
else:
# At toplevel, return this content type
return (cls._meta.app_label + "_" + cls.__name__).lower()
return (cls._meta.app_label + '_' + cls.__name__).lower()
@classmethod
def indexed_get_indexed_fields(cls):
@ -49,7 +49,7 @@ class Indexed(object):
if isinstance(indexed_fields, string_types):
indexed_fields = [indexed_fields]
if isinstance(indexed_fields, list):
indexed_fields = dict((field, dict(type="string")) for field in indexed_fields)
indexed_fields = dict((field, dict(type='string')) for field in indexed_fields)
if not isinstance(indexed_fields, dict):
raise ValueError()
@ -101,6 +101,13 @@ class Indexed(object):
# Add the field
search_fields.append(SearchField(field_name, boost=boost, partial_match=partial_match, es_extra=config))
# Remove any duplicate entries into search fields
# We need to take into account that fields can be indexed as both a SearchField and as a FilterField
search_fields_dict = {}
for field in search_fields:
search_fields_dict[(field.field_name, type(field))] = field
search_fields = search_fields_dict.values()
return search_fields
@classmethod
@ -132,7 +139,7 @@ class BaseField(object):
return self.get_attname(cls) + self.suffix
def __repr__(self):
return "<%s: %s>" % (self.__class__.__name__, self.field_name)
return '<%s: %s>' % (self.__class__.__name__, self.field_name)
class SearchField(BaseField):

View file

@ -25,13 +25,8 @@ class Command(BaseCommand):
# Loop through objects
for obj in model.objects.all():
# Check if this object has an "object_indexed" function
if hasattr(obj, "object_indexed"):
if obj.object_indexed() is False:
continue
# Get key for this object
key = toplevel_content_type + ":" + str(obj.pk)
key = toplevel_content_type + ':' + str(obj.pk)
# Check if this key already exists
if key in object_set:
@ -62,10 +57,8 @@ class Command(BaseCommand):
# Add objects to index
self.stdout.write("Adding objects")
results = s.add_bulk(object_set.values())
if results:
for result in results:
self.stdout.write(result[0] + ' ' + str(result[1]))
for result in s.add_bulk(object_set.values()):
self.stdout.write(result[0] + ' ' + str(result[1]))
# Refresh index
self.stdout.write("Refreshing index")

View file

@ -11,11 +11,6 @@ from wagtail.wagtailsearch.backends.db import DBSearch
from wagtail.wagtailsearch.backends import InvalidSearchBackendError
# Register wagtailsearch signal handlers
from wagtail.wagtailsearch import register_signal_handlers
register_signal_handlers()
class BackendTests(object):
# To test a specific backend, subclass BackendTests and define self.backend_path.
@ -41,21 +36,25 @@ class BackendTests(object):
testa = models.SearchTest()
testa.title = "Hello World"
testa.save()
self.backend.add(testa)
self.testa = testa
testb = models.SearchTest()
testb.title = "Hello"
testb.live = True
testb.save()
self.backend.add(testb)
testc = models.SearchTestChild()
testc.title = "Hello"
testc.live = True
testc.save()
self.backend.add(testc)
testd = models.SearchTestChild()
testd.title = "World"
testd.save()
self.backend.add(testd)
# Refresh the index
self.backend.refresh_index()
@ -130,6 +129,7 @@ class BackendTests(object):
def test_delete(self):
# Delete one of the objects
self.backend.delete(self.testa)
self.testa.delete()
# Refresh index