[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