Commit b9ecb657 authored by Andreas Jung's avatar Andreas Jung

- PluggableIndexes interface: + indexSize()

- browser for stored values for all UnIndex derived indexes
parents 224bd854 697662a2
...@@ -30,6 +30,13 @@ Zope Changes ...@@ -30,6 +30,13 @@ Zope Changes
Features added Features added
- PluginIndexes: the ZCatalog's "Indexes" tab now show the number of
distinct values indexed by each index instead of a mixture of indexed
objects versus number of distinct values. Indexes derived from UnIndex
show both values within their own ZMI screen. In addition most indexes
have now a "Browse" tab to browse through the list of indexed
values and their occurrences.
- FTPServer: a RNFR (rename from) request is now being responded - FTPServer: a RNFR (rename from) request is now being responded
with a 550 error code if the source file does not exist with a 550 error code if the source file does not exist
......
...@@ -88,17 +88,22 @@ class DateIndex(UnIndex, PropertyManager): ...@@ -88,17 +88,22 @@ class DateIndex(UnIndex, PropertyManager):
'mode':'w'},) 'mode':'w'},)
manage = manage_main = DTMLFile( 'dtml/manageDateIndex', globals() ) manage = manage_main = DTMLFile( 'dtml/manageDateIndex', globals() )
manage_browse = DTMLFile('../dtml/browseIndex', globals())
manage_main._setName( 'manage_main' ) manage_main._setName( 'manage_main' )
manage_options = ( { 'label' : 'Settings' manage_options = ( { 'label' : 'Settings'
, 'action' : 'manage_main' , 'action' : 'manage_main'
}, },
{'label': 'Browse',
'action': 'manage_browse',
},
) + PropertyManager.manage_options ) + PropertyManager.manage_options
def clear( self ): def clear( self ):
""" Complete reset """ """ Complete reset """
self._index = IOBTree() self._index = IOBTree()
self._unindex = OIBTree() self._unindex = OIBTree()
self._length.set(0)
def index_object( self, documentId, obj, threshold=None ): def index_object( self, documentId, obj, threshold=None ):
"""index an object, normalizing the indexed value to an integer """index an object, normalizing the indexed value to an integer
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<dtml-var manage_tabs> <dtml-var manage_tabs>
<p class="form-help"> <p class="form-help">
Nothing to manage at this time. Objects indexed: <dtml-var numObjects>
<br>
Distinct values: <dtml-var indexSize>
</p> </p>
......
...@@ -25,6 +25,7 @@ from OFS.SimpleItem import SimpleItem ...@@ -25,6 +25,7 @@ from OFS.SimpleItem import SimpleItem
from BTrees.IOBTree import IOBTree from BTrees.IOBTree import IOBTree
from BTrees.IIBTree import IISet, IITreeSet, union, intersection, multiunion from BTrees.IIBTree import IISet, IITreeSet, union, intersection, multiunion
import BTrees.Length
from Globals import package_home, DTMLFile, InitializeClass from Globals import package_home, DTMLFile, InitializeClass
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
...@@ -136,6 +137,7 @@ class DateRangeIndex(UnIndex): ...@@ -136,6 +137,7 @@ class DateRangeIndex(UnIndex):
self._since = IOBTree() self._since = IOBTree()
self._until = IOBTree() self._until = IOBTree()
self._unindex = IOBTree() # 'datum' will be a tuple of date ints self._unindex = IOBTree() # 'datum' will be a tuple of date ints
self._length = BTrees.Length.Length()
# #
# PluggableIndexInterface implementation (XXX inherit assertions?) # PluggableIndexInterface implementation (XXX inherit assertions?)
...@@ -310,10 +312,13 @@ class DateRangeIndex(UnIndex): ...@@ -310,10 +312,13 @@ class DateRangeIndex(UnIndex):
# #
security.declareProtected( VIEW_PERMISSION , 'numObjects' ) security.declareProtected( VIEW_PERMISSION , 'numObjects' )
def numObjects( self ): def numObjects( self ):
""" """ """
"""
return len( self._unindex ) return len( self._unindex )
def indexSize(self):
""" """
return len(self)
# #
# Helper functions. # Helper functions.
# #
......
...@@ -6,6 +6,12 @@ You can update this DateRangeIndex by editing the following field and clicking ...@@ -6,6 +6,12 @@ You can update this DateRangeIndex by editing the following field and clicking
<emUpdate</em>. <emUpdate</em>.
</p> </p>
<p>
Objects indexed: <dtml-var numObjects>
<br>
Distinct values: <dtml-var indexSize>
</p>
<form action="&dtml-URL1;/manage_edit" method="POST"> <form action="&dtml-URL1;/manage_edit" method="POST">
<table cellpadding="2" cellspacing="0" border="0"> <table cellpadding="2" cellspacing="0" border="0">
<tr> <tr>
......
...@@ -32,6 +32,9 @@ class FieldIndex(UnIndex): ...@@ -32,6 +32,9 @@ class FieldIndex(UnIndex):
{'label': 'Settings', {'label': 'Settings',
'action': 'manage_main', 'action': 'manage_main',
'help': ('FieldIndex','FieldIndex_Settings.stx')}, 'help': ('FieldIndex','FieldIndex_Settings.stx')},
{'label': 'Browse',
'action': 'manage_browse',
'help': ('FieldIndex','FieldIndex_Settings.stx')},
) )
query_options = ["query","range"] query_options = ["query","range"]
...@@ -39,6 +42,7 @@ class FieldIndex(UnIndex): ...@@ -39,6 +42,7 @@ class FieldIndex(UnIndex):
index_html = DTMLFile('dtml/index', globals()) index_html = DTMLFile('dtml/index', globals())
manage_workspace = DTMLFile('dtml/manageFieldIndex', globals()) manage_workspace = DTMLFile('dtml/manageFieldIndex', globals())
manage_browse = DTMLFile('../dtml/browseIndex', globals())
manage_addFieldIndexForm = DTMLFile('dtml/addFieldIndex', globals()) manage_addFieldIndexForm = DTMLFile('dtml/addFieldIndex', globals())
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<dtml-var manage_tabs> <dtml-var manage_tabs>
<p class="form-help"> <p class="form-help">
Nothing to manage at this time. Objects indexed: <dtml-var numObjects>
<br>
Distinct values: <dtml-var indexSize>
</p> </p>
......
...@@ -116,7 +116,7 @@ class TestCase( unittest.TestCase ): ...@@ -116,7 +116,7 @@ class TestCase( unittest.TestCase ):
assert len( self._index ) == len( values )-1 #'abce' is duplicate assert len( self._index ) == len( values )-1 #'abce' is duplicate
assert len( self._index.referencedObjects() ) == len( values ) assert len( self._index.referencedObjects() ) == len( values )
self.assertEqual(self._index.numObjects(), len( values )-1) self.assertEqual(self._index.indexSize(), len( values )-1)
assert self._index.getEntryForObject( 1234 ) is None assert self._index.getEntryForObject( 1234 ) is None
assert ( self._index.getEntryForObject( 1234, self._marker ) assert ( self._index.getEntryForObject( 1234, self._marker )
......
...@@ -34,6 +34,9 @@ class KeywordIndex(UnIndex): ...@@ -34,6 +34,9 @@ class KeywordIndex(UnIndex):
{'label': 'Settings', {'label': 'Settings',
'action': 'manage_main', 'action': 'manage_main',
'help': ('KeywordIndex','KeywordIndex_Settings.stx')}, 'help': ('KeywordIndex','KeywordIndex_Settings.stx')},
{'label': 'Browse',
'action': 'manage_browse',
'help': ('FieldIndex','FieldIndex_Settings.stx')},
) )
query_options = ("query","operator", "range") query_options = ("query","operator", "range")
...@@ -128,6 +131,7 @@ class KeywordIndex(UnIndex): ...@@ -128,6 +131,7 @@ class KeywordIndex(UnIndex):
index_html = DTMLFile('dtml/index', globals()) index_html = DTMLFile('dtml/index', globals())
manage_workspace = DTMLFile('dtml/manageKeywordIndex', globals()) manage_workspace = DTMLFile('dtml/manageKeywordIndex', globals())
manage_browse = DTMLFile('../dtml/browseIndex', globals())
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<dtml-var manage_tabs> <dtml-var manage_tabs>
<p class="form-help"> <p class="form-help">
Nothing to manage at this time. Objects indexed: <dtml-var numObjects>
<br>
Distinct values: <dtml-var indexSize>
</p> </p>
......
...@@ -142,7 +142,7 @@ class TestKeywordIndex( unittest.TestCase ): ...@@ -142,7 +142,7 @@ class TestKeywordIndex( unittest.TestCase ):
assert ( self._index.getEntryForObject( 1234, self._marker ) assert ( self._index.getEntryForObject( 1234, self._marker )
is self._marker ) is self._marker )
self._index.unindex_object( 1234 ) # nothrow self._index.unindex_object( 1234 ) # nothrow
self.assertEqual(self._index.numObjects(), len( values )-1) self.assertEqual(self._index.indexSize(), len( values )-1)
for k, v in values: for k, v in values:
entry = self._index.getEntryForObject( k ) entry = self._index.getEntryForObject( k )
......
...@@ -113,7 +113,6 @@ class PathIndex(Persistent, SimpleItem): ...@@ -113,7 +113,6 @@ class PathIndex(Persistent, SimpleItem):
comps = filter(None, path.split('/')) comps = filter(None, path.split('/'))
if not self._unindex.has_key(docid): if not self._unindex.has_key(docid):
self._migrate_length()
self._length.change(1) self._length.change(1)
for i in range(len(comps)): for i in range(len(comps)):
...@@ -146,7 +145,6 @@ class PathIndex(Persistent, SimpleItem): ...@@ -146,7 +145,6 @@ class PathIndex(Persistent, SimpleItem):
LOG.error('Attempt to unindex document with id %s failed' LOG.error('Attempt to unindex document with id %s failed'
% docid) % docid)
self._migrate_length()
self._length.change(-1) self._length.change(-1)
del self._unindex[docid] del self._unindex[docid]
...@@ -200,14 +198,15 @@ class PathIndex(Persistent, SimpleItem): ...@@ -200,14 +198,15 @@ class PathIndex(Persistent, SimpleItem):
return results return results
def numObjects(self): def numObjects(self):
""" return the number distinct values """
return len(self._unindex)
def indexSize(self):
""" return the number of indexed objects""" """ return the number of indexed objects"""
self._migrate_length() return len(self)
return self._length()
def _migrate_length(self): def __len__(self):
""" migrate index to use new _length attribute """ return self._length()
if not hasattr(self, '_length'):
self._length = Length(len(self._unindex))
def _apply_index(self, request, cid=''): def _apply_index(self, request, cid=''):
""" hook for (Z)Catalog """ hook for (Z)Catalog
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
<dtml-var manage_tabs> <dtml-var manage_tabs>
<p class="form-help"> <p class="form-help">
Nothing to manage at this time. Objects indexed: <dtml-var numObjects>
<br>
Distinct values: <dtml-var indexSize>
</p> </p>
......
...@@ -67,6 +67,9 @@ class PluggableIndexInterface(Interface.Base): ...@@ -67,6 +67,9 @@ class PluggableIndexInterface(Interface.Base):
def numObjects(): def numObjects():
"""Return the number of indexed objects""" """Return the number of indexed objects"""
def indexSize():
"""Return the size of the index in terms of distinct values"""
def clear(): def clear():
"""Empty the index""" """Empty the index"""
......
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<dtml-call "REQUEST.RESPONSE.setHeader('Content-Type', 'text/html; charset=UTF-8')" >
<p class="form-text">
The index "&dtml-getId;" contains <dtml-var items fmt=collection-length thousands_commas> distinct values
</p>
<dtml-let size="20"> <!-- batch size -->
<div class="form-text">
<dtml-in items previous size=size start=query_start >
<a href="&dtml-URL;?query_start=&dtml-previous-sequence-start-number;">
[Previous <dtml-var previous-sequence-size> entries]
</a>
</dtml-in>
<dtml-in items next size=size start=query_start >
<a href="&dtml-URL;?query_start=&dtml-next-sequence-start-number;">
[Next <dtml-var next-sequence-size> entries]
</a>
</dtml-in>
</div>
<table border="1" align="center" width="100%" class="form-help">
<dtml-in items start=query_start size=size>
<tr>
<td>
<dtml-if "meta_type in ('DateIndex',)">
<dtml-var "DateTime(_['sequence-key'])">
<dtml-else>
&dtml-sequence-key;
</dtml-if>
</td>
<td>
<ul>
<dtml-let v="_['sequence-item']">
<dtml-if "isinstance(v, int)">
<li><a href="<dtml-var "getpath(v)">"<dtml-var "getpath(v)"></a></li>
<dtml-else>
<dtml-in "v.keys()">
<li> <a href="<dtml-var "getpath(_['sequence-item'])">"><dtml-var "getpath(_['sequence-item'])"></a></li>
</dtml-in>
</dtml-if>
</dtml-let>
</ul>
</td>
</tr>
</dtml-in>
</table>
</dtml-let>
<dtml-var manage_page_footer>
...@@ -217,6 +217,10 @@ class ZCTextIndex(Persistent, Acquisition.Implicit, SimpleItem): ...@@ -217,6 +217,10 @@ class ZCTextIndex(Persistent, Acquisition.Implicit, SimpleItem):
"""Return number of unique words in the index""" """Return number of unique words in the index"""
return self.index.length() return self.index.length()
def indexSize(self):
"""Return the number of indexes objects """
return self.index.document_count()
def clear(self): def clear(self):
"""reinitialize the index (but not the lexicon)""" """reinitialize the index (but not the lexicon)"""
try: try:
......
...@@ -908,7 +908,8 @@ class ZCatalog(Folder, Persistent, Implicit): ...@@ -908,7 +908,8 @@ class ZCatalog(Folder, Persistent, Implicit):
__len__ changed in Zope 2.8. Pre-Zope 2.7 installation used to implement __len__ changed in Zope 2.8. Pre-Zope 2.7 installation used to implement
__len__ as persistent attribute of the index instance which is totally __len__ as persistent attribute of the index instance which is totally
incompatible with the new extension class implementation based on new-style incompatible with the new extension class implementation based on new-style
classes. classes. CMF indexes on date fields will be converted to DateIndex and
DateRangeIndex.
""" """
LOG.info('Start migration of indexes for %s' % self.absolute_url(1)) LOG.info('Start migration of indexes for %s' % self.absolute_url(1))
...@@ -925,6 +926,10 @@ class ZCatalog(Folder, Persistent, Implicit): ...@@ -925,6 +926,10 @@ class ZCatalog(Folder, Persistent, Implicit):
idx_type = idx.meta_type idx_type = idx.meta_type
idx_id = idx.getId() idx_id = idx.getId()
LOG.info('processing index %s' % idx_id) LOG.info('processing index %s' % idx_id)
if idx_type == 'FieldIndex' and idx_id in ('start', 'modified', 'end', 'created'):
idx_type = 'DateIndex'
if idx_type == 'FieldIndex' and idx_id in ('effective', 'expires'):
idx_type = 'DateRangeIndex'
indexed_attrs = getattr(idx, 'indexed_attrs', None) indexed_attrs = getattr(idx, 'indexed_attrs', None)
self.delIndex(idx.getId()) self.delIndex(idx.getId())
self.addIndex(idx_id, idx_type) self.addIndex(idx_id, idx_type)
......
...@@ -104,13 +104,13 @@ function toggleSelect() { ...@@ -104,13 +104,13 @@ function toggleSelect() {
</td> </td>
<td width="20%" align="left"><div class="list-item"><a <td width="20%" align="left"><div class="list-item"><a
href="./manage_catalogIndexes?skey=numObjects<dtml-if href="./manage_catalogIndexes?skey=indexSize<dtml-if
"rkey == ''">&rkey=numObjects</dtml-if "rkey == ''">&rkey=indexSize</dtml-if
>" >"
onMouseOver="window.status='Sort objects by number of indexed objects'; return true" onMouseOver="window.status='Sort objects by number of distinct values indexed'; return true"
onMouseOut="window.status=''; return true"><dtml-if onMouseOut="window.status=''; return true"><dtml-if
"skey == 'numObjects' or rkey == 'numObjects'" "skey == 'indexSize' or rkey == 'indexSize'"
><strong># objects</strong><dtml-else># objects</dtml-if></a></div> ><strong># distinct values</strong><dtml-else># distinct values</dtml-if></a></div>
</td> </td>
<td width="20%" align="left"><div class="list-item"><a <td width="20%" align="left"><div class="list-item"><a
...@@ -169,7 +169,7 @@ function toggleSelect() { ...@@ -169,7 +169,7 @@ function toggleSelect() {
<td> <td>
<div class="list-item"> <div class="list-item">
<dtml-var numObjects missing="n/a"> <dtml-var indexSize missing="n/a">
</div> </div>
</td> </td>
...@@ -183,6 +183,7 @@ function toggleSelect() { ...@@ -183,6 +183,7 @@ function toggleSelect() {
</tr> </tr>
</dtml-in> </dtml-in>
</table> </table>
<table cellspacing="0" cellpadding="2" border="0"> <table cellspacing="0" cellpadding="2" border="0">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment