[Zope] Searching multiple catalogs
Duncan Booth
duncan.booth at suttoncourtenay.org.uk
Fri Mar 18 06:26:00 EST 2005
I wrote some code to search multiple catalogs and merge the results, and
I've got it working, but I don't really understand why LazyCat works the
way it does, so I'm concerned in case there are situations where what I've
done won't work properly.
Normally when you search a catalog you get back a LazyMap which applies a
function to the appropriate result when you call __getitem__ so that it
appears to contain a list of brains but actually only creates them as
needed.
If you call searchResults with _merge=0 then you can call mergeResults with
multiple result sets and get back a LazyCat. Calling __getitem__ on the
LazyCat returns a 3-tuple and you can construct a brains object from the
tuple. What I don't understand is why LazyCat doesn't do that final step of
constructing the brains itself? In particular, does it mean that there is
some situation that I haven't hit yet where something else gets returned
and the brains cannot be constructed this way?
Since I want to use the same template to display search results whether
they come from one or several catalogs, I wrapped my result in a class to
convert the LazyCat elements into brains, and as I said above this seems to
work but I'm worried that since I don't really understand the thinking
behind this code there may be edge cases which break. Can anyone help
clarify this?
The code I've ended up with:
class LazyCatToBrains:
'''Lazycat returns tuples instead of converting to brains
so we need to convert the tuples into brains ourselves when a LazyCat
item is accessed.
'''
__allow_access_to_unprotected_subobjects__=1
def __init__(self, lc):
self.seq = lc
def __getitem__(self, index):
v = self.seq[index]
if isinstance(v, tuple) and len(v)==3:
v = v[2](v[1])
return v
def __getattr__(self, name):
return getattr(self.seq, name)
... the further down in the main class ...
# Based on code by Casey Duncan
security.declarePublic('queryMultipleCatalogs')
def queryMultipleCatalogs(self, request, *zcatalogs):
results = []
for zcat in zcatalogs:
results.append(zcat._catalog.searchResults(request, _merge=0))
sorted = request.has_key('sort-on') or request.has_key('sort_on')
reverse = ((request.get('sort-order','') or
request.get('sort_order','')).lower()
in ('reverse','descending'))
results= mergeResults(results, sorted, reverse)
return LazyCatToBrains(results)
and then the script which actually issues the query can just issue a query
directly to one catalogue or can query multiple catalogs and handle the
results identically:
if REQUEST.get('Occurrences')=='all':
catalogs = context.multisite_catalog, catalog
results = context.portal_indexer.queryMultipleCatalogs(query,
*catalogs)
else: #'this'
results=catalog(query)
More information about the Zope
mailing list