mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-13 11:30:59 +00:00
Merge pull request #348 from kaedroho/searchchanges/bits-and-pieces
Search Changes 7 - Some small changes
This commit is contained in:
commit
be31e8bf0b
6 changed files with 58 additions and 64 deletions
|
|
@ -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)),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue