use catalog's apply() method for querying (instead of searchResults()) - do not loose score (weight) information

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2547 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2008-04-26 12:49:12 +00:00
parent 21743d6e52
commit a0b8e4f39b
2 changed files with 41 additions and 32 deletions

View file

@ -22,9 +22,12 @@ Query management stuff.
$Id$ $Id$
""" """
from BTrees.IOBTree import IOBTree
from BTrees.IFBTree import weightedIntersection, weightedUnion, IFBucket
from zope import schema, component from zope import schema, component
from zope.interface import Interface, Attribute, implements from zope.interface import Interface, Attribute, implements
from zope.app.catalog.interfaces import ICatalog from zope.app.catalog.interfaces import ICatalog
from zope.app.intid.interfaces import IIntIds
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from cybertools.typology.interfaces import IType from cybertools.typology.interfaces import IType
@ -37,6 +40,16 @@ from loops import util
from loops.util import _ from loops.util import _
class ScoredSet(set):
def __init__(self, data=set(), scores={}):
super(ScoredSet, self).__init__(data)
self.scores = scores
def getScore(self, obj):
return self.scores.get(obj, -1)
class IQuery(Interface): class IQuery(Interface):
""" The basic query interface. """ The basic query interface.
""" """
@ -112,10 +125,12 @@ class FullQuery(BaseQuery):
def query(self, text=None, type=None, useTitle=True, useFull=False, def query(self, text=None, type=None, useTitle=True, useFull=False,
conceptTitle=None, conceptUid=None, conceptType=None, **kw): conceptTitle=None, conceptUid=None, conceptType=None, **kw):
result = set() result = set()
scores = {}
intids = component.getUtility(IIntIds)
rc = self.queryConceptsWithChildren(title=conceptTitle, uid=conceptUid, rc = self.queryConceptsWithChildren(title=conceptTitle, uid=conceptUid,
type=conceptType) type=conceptType)
if not rc and not text and '*' in type: # there should be some sort of selection... if not rc and not text and '*' in type: # there should be some sort of selection...
return result return ScoredSet(result, scores)
if text or type != 'loops:*': # TODO: this may be highly inefficient! if text or type != 'loops:*': # TODO: this may be highly inefficient!
cat = self.catalog cat = self.catalog
if type.endswith('*'): if type.endswith('*'):
@ -126,13 +141,21 @@ class FullQuery(BaseQuery):
criteria = {'loops_type': (start, end),} criteria = {'loops_type': (start, end),}
if useFull and text: if useFull and text:
criteria['loops_text'] = text criteria['loops_text'] = text
r1 = set(cat.searchResults(**criteria)) r1 = cat.apply(criteria) #r1 = set(cat.searchResults(**criteria))
else: else:
r1 = set() r1 = IFBucket() #r1 = set()
if useTitle and text: if useTitle and text:
if 'loops_text' in criteria:
del criteria['loops_text']
criteria['loops_title'] = text criteria['loops_title'] = text
r2 = set(cat.searchResults(**criteria)) r2 = cat.apply(criteria) #r2 = set(cat.searchResults(**criteria))
result = r1.union(r2) else:
r2 = IFBucket() #r2 = set()
x, uids = weightedUnion(r1, r2) #result = r1.union(r2)
for r, score in uids.items():
obj = intids.getObject(r)
result.add(obj)
scores[obj] = score
if rc is not None: if rc is not None:
if result: if result:
result = result.intersection(rc) result = result.intersection(rc)
@ -142,7 +165,7 @@ class FullQuery(BaseQuery):
if r.getLoopsRoot() == self.loopsRoot if r.getLoopsRoot() == self.loopsRoot
and canListObject(r) and canListObject(r)
and getVersion(r) == r) and getVersion(r) == r)
return result return ScoredSet(result, scores)
class ConceptQuery(BaseQuery): class ConceptQuery(BaseQuery):

View file

@ -99,33 +99,17 @@ Basic (text/title) search
The searchresults.html view, i.e. the SearchResults view class provides the The searchresults.html view, i.e. the SearchResults view class provides the
result set of the search via its `results` property. result set of the search via its `results` property.
Before accessing the `results` property we have to prepare a (for testing Before accessing the `results` property we have to prepare a
purposes fairly primitive) catalog and a resource we can search for: resource we can search for and index it in the catalog.
>>> from zope.app.catalog.interfaces import ICatalog
>>> class DummyCat(object):
... implements(ICatalog)
... def searchResults(self, **criteria):
... result = []
... name = criteria.get('loops_title')
... if name and name.endswith('*'): name = name[:-1]
... typeToken = criteria.get('loops_type', ('resource',))
... if name or typeToken:
... if 'concept' in typeToken[0]:
... if name:
... result = concepts.get(name)
... else:
... tp = concepts[typeToken[0].split(':')[-1]]
... result = list(tp.getChildren())
... else:
... result = resources.get(name)
... if not result: return []
... return type(result) is list and result or [result]
>>> component.provideUtility(DummyCat())
>>> from loops.resource import Resource >>> from loops.resource import Resource
>>> rplone = resources['plone'] = Resource() >>> rplone = resources['plone'] = Resource()
>>> from zope.app.catalog.interfaces import ICatalog
>>> from loops import util
>>> catalog = component.getUtility(ICatalog)
>>> catalog.index_doc(int(util.getUidForObject(rplone)), rplone)
>>> from loops.search.browser import SearchResults >>> from loops.search.browser import SearchResults
>>> form = {'search.2.title': True, 'search.2.text': u'plone'} >>> form = {'search.2.title': True, 'search.2.text': u'plone'}
>>> request = TestRequest(form=form) >>> request = TestRequest(form=form)
@ -155,6 +139,7 @@ resource (rplone) from above to one of the topics:
>>> cplone = concepts['plone'] = Concept(u'Plone') >>> cplone = concepts['plone'] = Concept(u'Plone')
>>> for c in (czope, czope2, czope3, cplone): >>> for c in (czope, czope2, czope3, cplone):
... c.conceptType = topic ... c.conceptType = topic
... catalog.index_doc(int(util.getUidForObject(c)), c)
>>> czope.assignChild(czope2) >>> czope.assignChild(czope2)
>>> czope.assignChild(czope3) >>> czope.assignChild(czope3)
>>> czope2.assignChild(cplone) >>> czope2.assignChild(cplone)
@ -164,7 +149,6 @@ Now we can fill our search form and execute the query; note that all concepts
found are listed, plus all their children and all resources associated found are listed, plus all their children and all resources associated
with them: with them:
>>> from loops import util
>>> uid = util.getUidForObject(concepts['zope']) >>> uid = util.getUidForObject(concepts['zope'])
>>> form = {'search.3.type': 'loops:concept:topic', 'search.3.text': uid} >>> form = {'search.3.type': 'loops:concept:topic', 'search.3.text': uid}
>>> request = TestRequest(form=form) >>> request = TestRequest(form=form)
@ -193,7 +177,7 @@ of the concepts' titles:
>>> request = TestRequest(form=form) >>> request = TestRequest(form=form)
>>> view = Search(page, request) >>> view = Search(page, request)
>>> view.listConcepts() >>> view.listConcepts()
u"{identifier: 'id', items: [{label: 'Zope (Topic)', name: 'Zope', id: '33'}]}" u"{identifier: 'id', items: [{label: 'Zope (Topic)', name: 'Zope', id: '34'}, {label: 'Zope 2 (Topic)', name: 'Zope 2', id: '37'}, {label: 'Zope 3 (Topic)', name: 'Zope 3', id: '39'}]}"
Preset Concept Types on Search Forms Preset Concept Types on Search Forms
------------------------------------ ------------------------------------
@ -211,7 +195,9 @@ Let's start with a new type, the customer type.
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation') >>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts') >>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts')
>>> for c in (cust1, cust2): c.conceptType = customer >>> for c in (cust1, cust2):
... c.conceptType = customer
... catalog.index_doc(int(util.getUidForObject(c)), c)
>>> from cybertools.typology.interfaces import IType >>> from cybertools.typology.interfaces import IType
>>> IType(cust1).qualifiers >>> IType(cust1).qualifiers