Skip to content

Commit

Permalink
transpose query integration into the catalog
Browse files Browse the repository at this point in the history
  • Loading branch information
andbag committed Sep 29, 2010
1 parent dc9be99 commit bee731e
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 76 deletions.
138 changes: 62 additions & 76 deletions src/Products/PluginIndexes/CompositeIndex/CompositeIndex.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,30 @@
from BTrees.IOBTree import IOBTree
import BTrees.Length

from zope.interface import implements

from ZODB.POSException import ConflictError

from Products.PluginIndexes.interfaces import ITransposeQuery
from Products.PluginIndexes.interfaces import IUniqueValueIndex
from Products.PluginIndexes.KeywordIndex.KeywordIndex import KeywordIndex
from Products.PluginIndexes.common.util import parseIndexRequest

from util import PermuteKeywordList

from config import PROJECTNAME


_marker = []

logger = logging.getLogger(PROJECTNAME)
logger = logging.getLogger('CompositeIndex')

class CompositeIndex(KeywordIndex):

"""Index for composition of simple fields.
or sequences of items
"""


implements(ITransposeQuery)

meta_type="CompositeIndex"

Expand Down Expand Up @@ -455,98 +459,80 @@ def items(self):
kw = self._tindex.get(k,k)
items.append((kw, v))
return items


manage = manage_main = DTMLFile('dtml/manageCompositeIndex', globals())
manage_main._setName('manage_main')
manage_browse = DTMLFile('dtml/browseIndex', globals())


manage_addCompositeIndexForm = DTMLFile('dtml/addCompositeIndex', globals())

def manage_addCompositeIndex(self, id, extra=None,
REQUEST=None, RESPONSE=None, URL3=None):
"""Add a composite index"""
return self.manage_addIndex(id, 'CompositeIndex', extra=extra, \
REQUEST=REQUEST, RESPONSE=RESPONSE, URL1=URL3)


def make_query(self, query):
""" optimize the query """

cquery = query.copy()

class compositeSearchArgumentsMap:
""" parse a request from the ZPublisher to optimize the query by means
of CompositeIndexes
"""
catalog = aq_parent(self)

keywords = {}

def __init__(self, catalog, request):
""" indexes -- dict of index objects
request -- the request dictionary send from the ZPublisher
"""

indexes = catalog.indexes

parent = aq_parent(catalog)

if parent.hasProperty('unimr.compositeindex') and not parent.getProperty('unimr.compositeindex',True):
logger.warn('skip compositeSearchArgumentsMap')
if parent.hasProperty('compositeindex') and not parent.getProperty('compositeindex',True):
logger.warn('skip make_query')
return

cRank=[]
for index in indexes.values():
if isinstance(index,CompositeIndex):

cId = index.id
logger.debug('CompositeIndex "%s" found' % cId)
# get indexes managed by CompositeIndex
cIdxs = index.getComponentIndexNames()
cRank.append((cId,cIdxs))

# sort from specific to unspecific CompositeIndex
cRank.sort(lambda x,y: cmp((len(y[1]),y[1]),(len(x[1]),x[1])))

for cId, cIdxs in cRank:
records=[]
for i in cIdxs:
index = indexes.get(i,None)
abort = False
cIdxs = self.getComponentIndexNames()

records=[]
for i in cIdxs:
index = indexes.get(i,None)
abort = False

if index:
rec = parseIndexRequest(request, index.id, index.query_options)
if index:
rec = parseIndexRequest(query, index.id, index.query_options)

if not IUniqueValueIndex.providedBy(index):
logger.warn('index %s: not an instance of IUniqueValueIndex' % index.id)
abort = True
if not IUniqueValueIndex.providedBy(index):
logger.warn('index %s: not an instance of IUniqueValueIndex' % index.id)
abort = True

if abort or rec.keys is None:
continue
if abort or rec.keys is None:
continue

records.append((i, rec))
records.append((i, rec))


# transform request only if more than one component of the composite key is applied
if len(records) > 1:
# transform request only if more than one component
# of the composite key is applied
if len(records) > 1:

cquery.update( { cId: { 'query': records }} )

query = { cId: { 'query': records } }

# delete obsolete query attributes from request
for i in cIdxs[:len(records)+1]:
if cquery.has_key(i):
del cquery[i]

logger.debug('composite query build "%s"' % query)
logger.debug('composite query build "%s"' % cquery)
return cquery

else:
logger.debug('only one component was affected, skip composite query build')


# delete obsolete query attributes from request
for i in cIdxs[:len(records)+1]:

if isinstance(request, dict):
if request.has_key(i):
del request[i]
else:
if request.keywords.has_key(i):
del request.keywords[i]
if isinstance(request.request, dict) and \
request.request.has_key(i):

del request.request[i]

request.keywords.update(query)

return query


manage = manage_main = DTMLFile('dtml/manageCompositeIndex', globals())
manage_main._setName('manage_main')
manage_browse = DTMLFile('dtml/browseIndex', globals())


manage_addCompositeIndexForm = DTMLFile('dtml/addCompositeIndex', globals())

def manage_addCompositeIndex(self, id, extra=None,
REQUEST=None, RESPONSE=None, URL3=None):
"""Add a composite index"""
return self.manage_addIndex(id, 'CompositeIndex', extra=extra, \
REQUEST=REQUEST, RESPONSE=RESPONSE, URL1=URL3)






10 changes: 10 additions & 0 deletions src/Products/PluginIndexes/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,13 @@ def getSettings(self):
E.g. {'indexed_attrs' : ('SearchableText', )}.
The interface does not define any specifc mapping keys.
"""


#
#
#

class ITransposeQuery(Interface):

def make_query(query):
""" returns optimized query for given index """
9 changes: 9 additions & 0 deletions src/Products/ZCatalog/Catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from Missing import MV
from Persistence import Persistent
from Products.PluginIndexes.interfaces import ILimitedResultIndex
from Products.PluginIndexes.interfaces import ITransposeQuery

import BTrees.Length
from BTrees.IIBTree import intersection, weightedIntersection, IISet
Expand Down Expand Up @@ -438,6 +439,7 @@ def getIndexDataForRID(self, rid):
def make_query(self, request):
# This is a bit of a mess, but the ZCatalog API has traditionally
# supported passing in query restrictions in almost arbitary ways

real_req = None
if isinstance(request, dict):
query = request.copy()
Expand Down Expand Up @@ -471,6 +473,13 @@ def make_query(self, request):
value = real_req.get(iid)
if value:
query[iid] = value

indexes = self.indexes.keys()
for i in indexes:
index = self.getIndex(i)
if ITransposeQuery.providedBy(index):
query = index.make_query(query)

return query

def _sorted_search_indexes(self, query):
Expand Down

0 comments on commit bee731e

Please sign in to comment.