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$
"""
from BTrees.IOBTree import IOBTree
from BTrees.IFBTree import weightedIntersection, weightedUnion, IFBucket
from zope import schema, component
from zope.interface import Interface, Attribute, implements
from zope.app.catalog.interfaces import ICatalog
from zope.app.intid.interfaces import IIntIds
from zope.cachedescriptors.property import Lazy
from cybertools.typology.interfaces import IType
@ -37,6 +40,16 @@ from loops import util
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):
""" The basic query interface.
"""
@ -112,10 +125,12 @@ class FullQuery(BaseQuery):
def query(self, text=None, type=None, useTitle=True, useFull=False,
conceptTitle=None, conceptUid=None, conceptType=None, **kw):
result = set()
scores = {}
intids = component.getUtility(IIntIds)
rc = self.queryConceptsWithChildren(title=conceptTitle, uid=conceptUid,
type=conceptType)
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!
cat = self.catalog
if type.endswith('*'):
@ -126,13 +141,21 @@ class FullQuery(BaseQuery):
criteria = {'loops_type': (start, end),}
if useFull and text:
criteria['loops_text'] = text
r1 = set(cat.searchResults(**criteria))
r1 = cat.apply(criteria) #r1 = set(cat.searchResults(**criteria))
else:
r1 = set()
r1 = IFBucket() #r1 = set()
if useTitle and text:
if 'loops_text' in criteria:
del criteria['loops_text']
criteria['loops_title'] = text
r2 = set(cat.searchResults(**criteria))
result = r1.union(r2)
r2 = cat.apply(criteria) #r2 = set(cat.searchResults(**criteria))
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 result:
result = result.intersection(rc)
@ -142,7 +165,7 @@ class FullQuery(BaseQuery):
if r.getLoopsRoot() == self.loopsRoot
and canListObject(r)
and getVersion(r) == r)
return result
return ScoredSet(result, scores)
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
result set of the search via its `results` property.
Before accessing the `results` property we have to prepare a (for testing
purposes fairly primitive) catalog and a resource we can search for:
>>> 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())
Before accessing the `results` property we have to prepare a
resource we can search for and index it in the catalog.
>>> from loops.resource import 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
>>> form = {'search.2.title': True, 'search.2.text': u'plone'}
>>> request = TestRequest(form=form)
@ -155,6 +139,7 @@ resource (rplone) from above to one of the topics:
>>> cplone = concepts['plone'] = Concept(u'Plone')
>>> for c in (czope, czope2, czope3, cplone):
... c.conceptType = topic
... catalog.index_doc(int(util.getUidForObject(c)), c)
>>> czope.assignChild(czope2)
>>> czope.assignChild(czope3)
>>> 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
with them:
>>> from loops import util
>>> uid = util.getUidForObject(concepts['zope'])
>>> form = {'search.3.type': 'loops:concept:topic', 'search.3.text': uid}
>>> request = TestRequest(form=form)
@ -193,7 +177,7 @@ of the concepts' titles:
>>> request = TestRequest(form=form)
>>> view = Search(page, request)
>>> 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
------------------------------------
@ -211,7 +195,9 @@ Let's start with a new type, the customer type.
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
>>> 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
>>> IType(cust1).qualifiers