[z3-checkins] r26869 - z3/hurry/trunk/src/hurry/query
srichter at codespeak.net
srichter at codespeak.net
Sat May 6 14:53:03 CEST 2006
Author: srichter
Date: Sat May 6 14:53:01 2006
New Revision: 26869
Added:
z3/hurry/trunk/src/hurry/query/value.py (contents, props changed)
Modified:
z3/hurry/trunk/src/hurry/query/query.py
z3/hurry/trunk/src/hurry/query/query.txt
z3/hurry/trunk/src/hurry/query/set.py
Log:
- Implemented queries for the ``zc.catalog`` module's ``ValueIndex``. It
pretty much does the same as the ``FieldIndex`` queries, except that
it supports the additional features of the value index, such as
extents, exclude_min and exclude_max.
- Soem whitespace cleanup.
Martijn, I hope you are okay with those changes. I think that we
eventually want to merge the ``set`` and ``value`` module queries into
the main ones as to not duplicate so much of the API.
Modified: z3/hurry/trunk/src/hurry/query/query.py
==============================================================================
--- z3/hurry/trunk/src/hurry/query/query.py (original)
+++ z3/hurry/trunk/src/hurry/query/query.py Sat May 6 14:53:01 2006
@@ -15,7 +15,7 @@
class Query(object):
implements(interfaces.IQuery)
-
+
def searchResults(self, query):
results = query.apply()
if results is not None:
@@ -29,7 +29,7 @@
def __rand__(self, other):
return And(other, self)
-
+
def __or__(self, other):
return Or(self, other)
@@ -38,7 +38,7 @@
def __invert__(self):
return Not(self)
-
+
class And(Term):
def __init__(self, *terms):
self.terms = terms
@@ -63,13 +63,13 @@
for _, r in results:
_, result = weightedIntersection(result, r)
return result
-
+
class Or(Term):
def __init__(self, *terms):
self.terms = terms
def apply(self):
- results = []
+ results = []
for term in self.terms:
r = term.apply()
# empty results
@@ -91,7 +91,7 @@
def __init__(self, term):
self.term = term
- def apply(self):
+ def apply(self):
return difference(self._all(), self.term.apply())
def _all(self):
@@ -123,17 +123,17 @@
index = super(Text, self).getIndex()
assert ITextIndex.providedBy(index)
return index
-
+
def apply(self):
index = self.getIndex()
return index.apply(self.text)
-
+
class FieldTerm(IndexTerm):
def getIndex(self):
index = super(FieldTerm, self).getIndex()
assert IFieldIndex.providedBy(index)
return index
-
+
class Eq(FieldTerm):
def __init__(self, index_id, value):
assert value is not None
@@ -176,7 +176,7 @@
assert None not in values
super(In, self).__init__(index_id)
self.values = values
-
+
def apply(self):
results = []
index = self.getIndex()
Modified: z3/hurry/trunk/src/hurry/query/query.txt
==============================================================================
--- z3/hurry/trunk/src/hurry/query/query.txt (original)
+++ z3/hurry/trunk/src/hurry/query/query.txt Sat May 6 14:53:01 2006
@@ -40,7 +40,7 @@
easily. By including the __cmp__ method we make sure search results
can be stably sorted.
-We use a fake int id utility here so we can test independent of
+We use a fake int id utility here so we can test independent of
the full-blown zope environment::
>>> from zope.interface import verify
@@ -98,7 +98,7 @@
... Content(6, 'Y', 'Z')]
And catalog them now::
-
+
>>> for entry in content:
... catalog.index_doc(intid.register(entry), entry)
@@ -168,7 +168,7 @@
Using and (&)::
- >>> f2 = ('catalog1', 'f2')
+ >>> f2 = ('catalog1', 'f2')
>>> displayQuery(Eq(f1, 'a') & Eq(f2, 'b'))
[1, 4]
@@ -209,6 +209,7 @@
>>> displayQuery(In(f1, ['a', 'X', 'Y', 'Z']) & In(f1, ['Z']))
[]
+
SetIndex queries
----------------
@@ -267,3 +268,127 @@
>>> displayQuery(AnyOf(f1, ['a']) & Eq(f2, 1))
[1, 2]
+
+
+ValueIndex queries
+------------------
+
+The ``ValueIndex`` is defined in ``zc.catalog`` and provides a generalization
+of the standard field index.
+
+ >>> from hurry.query import value
+
+Let's set up a catalog that uses this index. The ``ValueIndex`` is defined in
+``zc.catalog``. Let's make a catalog which uses it:
+
+ >>> intid = DummyIntId()
+ >>> ztapi.provideUtility(zope.app.intid.interfaces.IIntIds, intid)
+
+ >>> from zope.app.catalog.interfaces import ICatalog
+ >>> from zope.app.catalog.catalog import Catalog
+ >>> catalog = Catalog()
+ >>> ztapi.provideUtility(ICatalog, catalog, 'catalog1')
+
+ >>> from zc.catalog.catalogindex import ValueIndex
+ >>> catalog['f1'] = ValueIndex('f1', IContent)
+
+Next we set up some content data to fill the indices:
+
+ >>> content = [
+ ... Content(1, 'a'),
+ ... Content(2, 'b'),
+ ... Content(3, 'c'),
+ ... Content(4, 'd'),
+ ... Content(5, 'c'),
+ ... Content(6, 'a')]
+
+And catalog them now:
+
+ >>> for entry in content:
+ ... catalog.index_doc(intid.register(entry), entry)
+
+
+Let's now query for all objects where ``f1`` equals 'a':
+
+ >>> f1 = ('catalog1', 'f1')
+ >>> displayQuery(value.Eq(f1, 'a'))
+ [1, 6]
+
+Next, let's find all objects where ``f1`` does not equal 'a'; this is more
+efficient than the generic ``~`` operator:
+
+ >>> displayQuery(value.NotEq(f1, 'a'))
+ [2, 3, 4, 5]
+
+You can also query for all objects where the value of ``f1`` is in a set of
+values:
+
+ >>> displayQuery(value.In(f1, ['a', 'd']))
+ [1, 4, 6]
+
+The next interesting set of queries allows you to make evaluations of the
+values. For example, you can ask for all objects between a certain set of
+values:
+
+ >>> displayQuery(value.Between(f1, 'a', 'c'))
+ [1, 2, 3, 5, 6]
+
+ >>> displayQuery(value.Between(f1, 'a', 'c', exclude_min=True))
+ [2, 3, 5]
+
+ >>> displayQuery(value.Between(f1, 'a', 'c', exclude_max=True))
+ [1, 2, 6]
+
+ >>> displayQuery(value.Between(f1, 'a', 'c',
+ ... exclude_min=True, exclude_max=True))
+ [2]
+
+You can also leave out one end of the range:
+
+ >>> displayQuery(value.Between(f1, 'c', None))
+ [3, 4, 5]
+ >>> displayQuery(value.Between(f1, None, 'c'))
+ [1, 2, 3, 5, 6]
+
+You can also use greater-equals and lesser-equals for the same purpose:
+
+ >>> displayQuery(value.Ge(f1, 'c'))
+ [3, 4, 5]
+ >>> displayQuery(value.Le(f1, 'c'))
+ [1, 2, 3, 5, 6]
+
+Of course, you can chain those queries with the others as demonstrated before.
+
+The ``value`` module also supports ``zc.catalog`` extents. The first query is
+``ExtentAny``, which returns all douments matching the extent. If the the
+extent is ``None``, all document ids are returned:
+
+ >>> displayQuery(value.ExtentAny(f1, None))
+ [1, 2, 3, 4, 5, 6]
+
+If we now create an extent that is only in the scope of the first four
+documents,
+
+ >>> from zc.catalog.extentcatalog import FilterExtent
+ >>> extent = FilterExtent(lambda extent, uid, obj: True)
+ >>> for i in range(4):
+ ... extent.add(i, i)
+
+then only the first four are returned:
+
+ >>> displayQuery(value.ExtentAny(f1, extent))
+ [1, 2, 3, 4]
+
+The opposite query is the ``ExtentNone`` query, which returns all ids in the
+extent that are *not* in the index:
+
+ >>> id = intid.register(Content(7, 'b'))
+ >>> id = intid.register(Content(8, 'c'))
+ >>> id = intid.register(Content(9, 'a'))
+
+ >>> extent = FilterExtent(lambda extent, uid, obj: True)
+ >>> for i in range(9):
+ ... extent.add(i, i)
+
+ >>> displayQuery(value.ExtentNone(f1, extent))
+ [7, 8, 9]
Modified: z3/hurry/trunk/src/hurry/query/set.py
==============================================================================
--- z3/hurry/trunk/src/hurry/query/set.py (original)
+++ z3/hurry/trunk/src/hurry/query/set.py Sat May 6 14:53:01 2006
@@ -6,12 +6,12 @@
index = super(SetTerm, self).getIndex()
assert ISetIndex.providedBy(index)
return index
-
+
class AnyOf(SetTerm):
def __init__(self, index_id, values):
super(AnyOf, self).__init__(index_id)
self.values = values
-
+
def apply(self):
return self.getIndex().apply({'any_of': self.values})
Added: z3/hurry/trunk/src/hurry/query/value.py
==============================================================================
--- (empty file)
+++ z3/hurry/trunk/src/hurry/query/value.py Sat May 6 14:53:01 2006
@@ -0,0 +1,79 @@
+from zc.catalog.interfaces import IValueIndex
+from hurry.query import query
+
+class ValueTerm(query.IndexTerm):
+ def getIndex(self):
+ index = super(ValueTerm, self).getIndex()
+ assert IValueIndex.providedBy(index)
+ return index
+
+class Eq(ValueTerm):
+ def __init__(self, index_id, value):
+ assert value is not None
+ super(Eq, self).__init__(index_id)
+ self.value = value
+
+ def apply(self):
+ return self.getIndex().apply({'any_of': (self.value,)})
+
+class NotEq(ValueTerm):
+ def __init__(self, index_id, not_value):
+ super(NotEq, self).__init__(index_id)
+ self.not_value = not_value
+
+ def apply(self):
+ index = self.getIndex()
+ values = list(index.values())
+ values.remove(self.not_value)
+ return index.apply({'any_of': values})
+
+class Between(ValueTerm):
+ def __init__(self, index_id, min_value=None, max_value=None,
+ exclude_min=False, exclude_max=False):
+ super(Between, self).__init__(index_id)
+ self.min_value = min_value
+ self.max_value = max_value
+ self.exclude_min = exclude_min
+ self.exclude_max = exclude_max
+
+ def apply(self):
+ return self.getIndex().apply(
+ {'between': (self.min_value, self.max_value,
+ self.exclude_min, self.exclude_max)})
+
+class Ge(Between):
+ def __init__(self, index_id, min_value):
+ super(Ge, self).__init__(index_id, min_value=min_value)
+
+class Le(Between):
+ def __init__(self, index_id, max_value):
+ super(Le, self).__init__(index_id, max_value=max_value)
+
+class In(ValueTerm):
+ def __init__(self, index_id, values):
+ assert None not in values
+ super(In, self).__init__(index_id)
+ self.values = values
+
+ def apply(self):
+ return self.getIndex().apply({'any_of': self.values})
+
+class ExtentAny(ValueTerm):
+ """Any ids in the extent that are indexed by this index.
+ """
+ def __init__(self, index_id, extent):
+ super(ExtentAny, self).__init__(index_id)
+ self.extent = extent
+
+ def apply(self):
+ return self.getIndex().apply({'any': self.extent})
+
+class ExtentNone(ValueTerm):
+ """Any ids in the extent that are not indexed by this index.
+ """
+ def __init__(self, index_id, extent):
+ super(ExtentNone, self).__init__(index_id)
+ self.extent = extent
+
+ def apply(self):
+ return self.getIndex().apply({'none': self.extent})
More information about the z3-checkins
mailing list