[Zope-Checkins] SVN: Zope/trunk/lib/python/Products/ZCatalog/ Port bugfix for mergeResults KeyError bug with small sort indexes.

Casey Duncan casey at zope.com
Tue May 18 11:08:44 EDT 2004


Log message for revision 24804:
Port bugfix for mergeResults KeyError bug with small sort indexes.
Port mergeResults() tests



-=-
Modified: Zope/trunk/lib/python/Products/ZCatalog/Catalog.py
===================================================================
--- Zope/trunk/lib/python/Products/ZCatalog/Catalog.py	2004-05-18 14:33:35 UTC (rev 24803)
+++ Zope/trunk/lib/python/Products/ZCatalog/Catalog.py	2004-05-18 15:08:43 UTC (rev 24804)
@@ -592,7 +592,8 @@
             rs = rs.keys()
         rlen = len(rs)
         
-        if limit is None and (rlen > (len(sort_index) * (rlen / 100 + 1))):
+        if merge and limit is None and (
+            rlen > (len(sort_index) * (rlen / 100 + 1))):
             # The result set is much larger than the sorted index,
             # so iterate over the sorted index for speed.
             # This is rarely exercised in practice...
@@ -620,13 +621,10 @@
                     append((k, intset, _self__getitem__))
                     # Note that sort keys are unique.
             
-            if merge:
-                result.sort()
-                if reverse:
-                    result.reverse()
-                result = LazyCat(LazyValues(result), length)
-            else:
-                return result            
+            result.sort()
+            if reverse:
+                result.reverse()
+            result = LazyCat(LazyValues(result), length)
         elif limit is None or (limit * 4 > rlen):
             # Iterate over the result set getting sort keys from the index
             for did in rs:

Modified: Zope/trunk/lib/python/Products/ZCatalog/tests/testCatalog.py
===================================================================
--- Zope/trunk/lib/python/Products/ZCatalog/tests/testCatalog.py	2004-05-18 14:33:35 UTC (rev 24803)
+++ Zope/trunk/lib/python/Products/ZCatalog/tests/testCatalog.py	2004-05-18 15:08:43 UTC (rev 24804)
@@ -5,6 +5,7 @@
 import os
 import random
 import unittest
+from itertools import chain
 
 import ZODB, OFS.Application
 from ZODB.DemoStorage import DemoStorage
@@ -41,25 +42,11 @@
 
 app = createDatabase()
 
+def sort(iterable):
+    L = list(iterable)
+    L.sort()
+    return L
 
-################################################################################
-# Stuff of Chris
-# XXX What's this mean?  What does this comment apply to?
-################################################################################
-
-# XXX These imports and class don't appear to be needed?
-## from AccessControl.SecurityManagement import newSecurityManager
-## from AccessControl.SecurityManagement import noSecurityManager
-
-## class DummyUser:
-
-##     def __init__( self, name ):
-##         self._name = name
-
-##     def getUserName( self ):
-##         return self._name
-
-
 class CatalogBase:
     def setUp(self):
         self._vocabulary = Vocabulary.Vocabulary('Vocabulary', 'Vocabulary',
@@ -445,7 +432,7 @@
     def __init__(self,num):
         self.number = num
 
-class testRS(unittest.TestCase):
+class TestRS(unittest.TestCase):
 
     def setUp(self):
         self._vocabulary = Vocabulary.Vocabulary('Vocabulary','Vocabulary'
@@ -472,14 +459,94 @@
                 self.assert_(m<=size and size<=n,
                              "%d vs [%d,%d]" % (r.number,m,n))
 
-
+class TestMerge(unittest.TestCase):
+    # Test merging results from multiple catalogs
+    
+    def setUp(self):
+        vocabulary = Vocabulary.Vocabulary(
+            'Vocabulary','Vocabulary', globbing=1)
+        self.catalogs = []
+        for i in range(3):
+            cat = Catalog()
+            cat.addIndex('num', FieldIndex('num'))
+            cat.addIndex('big', FieldIndex('big'))
+            cat.addIndex('title', TextIndex('title'))
+            cat.vocabulary = vocabulary
+            cat.aq_parent = zdummy(16336)
+            for i in range(10):
+                obj = zdummy(i)
+                obj.big = i > 5
+                cat.catalogObject(obj, str(i))
+            self.catalogs.append(cat)
+    
+    def testNoFilterOrSort(self):
+        from Products.ZCatalog.Catalog import mergeResults
+        results = [cat.searchResults(_merge=0) for cat in self.catalogs]
+        merged_rids = [r.getRID() for r in mergeResults(
+            results, has_sort_keys=False, reverse=False)]
+        expected = [r.getRID() for r in chain(*results)]
+        self.assertEqual(sort(merged_rids), sort(expected))
+    
+    def testSortedOnly(self):
+        from Products.ZCatalog.Catalog import mergeResults
+        results = [cat.searchResults(sort_on='num', _merge=0) 
+                   for cat in self.catalogs]
+        merged_rids = [r.getRID() for r in mergeResults(
+            results, has_sort_keys=True, reverse=False)]
+        expected = sort(chain(*results))
+        expected = [rid for sortkey, rid, getitem in expected]
+        self.assertEqual(merged_rids, expected)
+    
+    def testSortReverse(self):
+        from Products.ZCatalog.Catalog import mergeResults
+        results = [cat.searchResults(sort_on='num', _merge=0) 
+                   for cat in self.catalogs]
+        merged_rids = [r.getRID() for r in mergeResults(
+            results, has_sort_keys=True, reverse=True)]
+        expected = sort(chain(*results))
+        expected.reverse()
+        expected = [rid for sortkey, rid, getitem in expected]
+        self.assertEqual(merged_rids, expected)
+    
+    def testLimitSort(self):
+        from Products.ZCatalog.Catalog import mergeResults
+        results = [cat.searchResults(sort_on='num', sort_limit=2, _merge=0) 
+                   for cat in self.catalogs]
+        merged_rids = [r.getRID() for r in mergeResults(
+            results, has_sort_keys=True, reverse=False)]
+        expected = sort(chain(*results))
+        expected = [rid for sortkey, rid, getitem in expected]
+        self.assertEqual(merged_rids, expected)
+    
+    def testScored(self):
+        from Products.ZCatalog.Catalog import mergeResults
+        results = [cat.searchResults(title='4 or 5 or 6', _merge=0) 
+                   for cat in self.catalogs]
+        merged_rids = [r.getRID() for r in mergeResults(
+            results, has_sort_keys=True, reverse=False)]
+        expected = sort(chain(*results))
+        expected = [rid for sortkey, (nscore, score, rid), getitem in expected]
+        self.assertEqual(merged_rids, expected)
+        
+    def testSmallIndexSort(self):
+        # Test that small index sort optimization is not used for merging
+        from Products.ZCatalog.Catalog import mergeResults
+        results = [cat.searchResults(sort_on='big', _merge=0) 
+                   for cat in self.catalogs]
+        merged_rids = [r.getRID() for r in mergeResults(
+            results, has_sort_keys=True, reverse=False)]
+        expected = sort(chain(*results))
+        expected = [rid for sortkey, rid, getitem in expected]
+        self.assertEqual(merged_rids, expected)
+    
 def test_suite():
     suite = unittest.TestSuite()
     suite.addTest( unittest.makeSuite( TestAddDelColumn ) )
     suite.addTest( unittest.makeSuite( TestAddDelIndexes ) )
     suite.addTest( unittest.makeSuite( TestZCatalog ) )
     suite.addTest( unittest.makeSuite( TestCatalogObject ) )
-    suite.addTest( unittest.makeSuite( testRS ) )
+    suite.addTest( unittest.makeSuite( TestRS ) )
+    suite.addTest( unittest.makeSuite( TestMerge ) )
     return suite
 
 if __name__ == '__main__':




More information about the Zope-Checkins mailing list