Search a Catalog in Python
Dear Zopers This time, I thought it should be simple, but I am struggling again: The idea was to search for items that have been catalogued successfully. In the Zope Book they describe how to do this using form and scripts. That works for me, too, but then I need to search in a regular Python program (An FS product). For this purpose, I found the ZCatalog.search method and gave it a try, but I cannot get it to work. It expects a dictionary, but what does that contain? Here is what I have so far: __init__(self, id, title, ...): ... # add a Catalog _catalog = ZCatalog('Catalog') # add Metadata fields for the Catalog _catalog.addColumn('id') _catalog.addColumn('title') _catalog.addColumn('icon') # PathIndex _catalog.addIndex('path_index', 'PathIndex') # ZCTextIndex (with the required Lexicon) class Extra: """ Just a dummy to build records for the Lexicon. """ pass extra = Extra() extra.index_type = 'Okapi BM25 Rank' extra.lexicon_id = 'Lexicon' _catalog._setObject('Lexicon', PLexicon('Lexicon', '', Splitter(), CaseNormalizer())) _catalog.addIndex('title', 'ZCTextIndex', extra) # FieldIndex _catalog.addIndex('composer_first_name_index', 'FieldIndex', 'first_name') _catalog.addIndex('composer_last_name_index', 'FieldIndex', 'last_name') _catalog.addIndex('composer_year_of_birth_index', 'FieldIndex', 'year_of_birth') self._setObject('Catalog', _catalog) ... # all new items get catalogued (verified) and now we should be able to search for them like this (???): def searchForAnItem(item) obj=self.Catalog(id={'query':[item]}) What is wrong here? I feel very stupid again. Any help is appreciated! Thanks and kind regards Andre
Hi I am doing something similarly. def __searchCatalog(self, p_criteria): """Search catalog""" return self.__catalog(p_criteria) This returns a list of mybrains objects. def __getFoundObjects(self, p_list): """gets objects from catalog results""" return map(self.__catalog.getobject, map(getattr, p_list, ('data_record_id_',)*len(p_list))) It gets a list of mybrains objects and returns a list of zope objects. So, to search the catalog (in my case the __catalog is the ZCatalog instance): results = self.__getFoundObjects(self.__catalog(filter)) The filter mut be a dictionary, something like: {'meta_type': 'File'}. I think that you must write like: obj=self.Catalog('id':item} if you want to search by id. Hope this will help Dragos
Dear Zopers
This time, I thought it should be simple, but I am struggling again: The idea was to search for items that have been catalogued successfully. In the Zope Book they describe how to do this using form and scripts. That works for me, too, but then I need to search in a regular Python program (An FS product). For this purpose, I found the ZCatalog.search method and gave it a try, but I cannot get it to work. It expects a dictionary, but what does that contain?
Here is what I have so far:
__init__(self, id, title, ...): ... # add a Catalog _catalog = ZCatalog('Catalog')
# add Metadata fields for the Catalog _catalog.addColumn('id') _catalog.addColumn('title') _catalog.addColumn('icon')
# PathIndex _catalog.addIndex('path_index', 'PathIndex')
# ZCTextIndex (with the required Lexicon) class Extra: """ Just a dummy to build records for the Lexicon. """ pass extra = Extra() extra.index_type = 'Okapi BM25 Rank' extra.lexicon_id = 'Lexicon' _catalog._setObject('Lexicon', PLexicon('Lexicon', '', Splitter(), CaseNormalizer())) _catalog.addIndex('title', 'ZCTextIndex', extra)
# FieldIndex _catalog.addIndex('composer_first_name_index', 'FieldIndex', 'first_name') _catalog.addIndex('composer_last_name_index', 'FieldIndex', 'last_name') _catalog.addIndex('composer_year_of_birth_index', 'FieldIndex', 'year_of_birth')
self._setObject('Catalog', _catalog)
... # all new items get catalogued (verified) and now we should be able to search for them like this (???):
def searchForAnItem(item) obj=self.Catalog(id={'query':[item]})
What is wrong here? I feel very stupid again. Any help is appreciated!
Thanks and kind regards Andre
_______________________________________________ Zope maillist - Zope@zope.org http://mail.zope.org/mailman/listinfo/zope ** No cross posts or HTML encoding! ** (Related lists - http://mail.zope.org/mailman/listinfo/zope-announce http://mail.zope.org/mailman/listinfo/zope-dev )
Dragos Chirila wrote:
Hi
I am doing something similarly.
def __searchCatalog(self, p_criteria): """Search catalog""" return self.__catalog(p_criteria)
This returns a list of mybrains objects.
def __getFoundObjects(self, p_list): """gets objects from catalog results""" return map(self.__catalog.getobject, map(getattr, p_list, ('data_record_id_',)*len(p_list)))
It gets a list of mybrains objects and returns a list of zope objects.
Hmm! I think that is a questionable approach. If an object is in the catalog, but has been deleted from the ZODB, you will get an error. I have had this happen a few times, and it is irritating. I don't know how it can happen. Perhaps poorly written products can do it. I dont remember. This approach should be failsafe result = [] for brain in brains: try: obj = brain.getObject() result.append(obj) except: # Will probably raise AttributeError on None object pass -- hilsen/regards Max M, Denmark http://www.mxm.dk/ IT's Mad Science
Max M wrote:
Dragos Chirila wrote:
Hi
I am doing something similarly.
def __searchCatalog(self, p_criteria): """Search catalog""" return self.__catalog(p_criteria)
This returns a list of mybrains objects.
def __getFoundObjects(self, p_list): """gets objects from catalog results""" return map(self.__catalog.getobject, map(getattr, p_list, ('data_record_id_',)*len(p_list)))
It gets a list of mybrains objects and returns a list of zope objects.
Hmm! I think that is a questionable approach.
Indeed, yuk! Don't really know why you're hiding your catalog away in __catalog. Why not just make your code ObjectManager or Folderish and put your catalog in there? As for "getting found objects": return [brain.getObject() for brain in self.__catalog(p_criteria)] ...seems a LOT nicer to me. Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
I'm hiding the catalog object because I don't want to be dependent of a Catalog object in my folderish object or the object Catalog in the ROOT or you name it. I need this hidden catalog object to catalog only what I want and to do exactly what I need. In this way I am sure that I cannot have problems like: objects cataloged but deleted from Zope and a lot others. The hidden catalog will index only objects that I want to search with it. These objects know to catalog, recatalog or uncatalog automatically(how? very easy, overwrite manage_afterAdd for catalog object when is created, manage_beforeDelete for uncatalog object when is deleted). Using this hidden catalog object the performance is increased, because it handles only my product objects. When the product is delivered, the catalog is configured automatically (all the indexes and metadata are present), no need for the user to do any additional settings. Let's suppose you build your folderish product based on a catalog object in the ROOT. What happens if the somebody index objects other than I need? Or worse, deletes the catalog object? The same problem if I put the catalog object in my folderish product. Another thing: I need certains indexes for my catalog, not all the indexes that could be present in a catalog object in ROOT. Anyway, my product is totally independent of other Zope objects.
return [brain.getObject() for brain in self.__catalog(p_criteria)] Looks nicer indeed. I will give it a try.
Dragos
Max M wrote:
Dragos Chirila wrote:
Hi
I am doing something similarly.
def __searchCatalog(self, p_criteria): """Search catalog""" return self.__catalog(p_criteria)
This returns a list of mybrains objects.
def __getFoundObjects(self, p_list): """gets objects from catalog results""" return map(self.__catalog.getobject, map(getattr, p_list, ('data_record_id_',)*len(p_list)))
It gets a list of mybrains objects and returns a list of zope objects.
Hmm! I think that is a questionable approach.
Indeed, yuk! Don't really know why you're hiding your catalog away in __catalog. Why not just make your code ObjectManager or Folderish and put your catalog in there?
As for "getting found objects":
return [brain.getObject() for brain in self.__catalog(p_criteria)]
...seems a LOT nicer to me.
Chris
-- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Chris Withers wrote:
return [brain.getObject() for brain in self.__catalog(p_criteria)]
...seems a LOT nicer to me.
You should at least check that getObject() does not return a None object. Which it can *very* easily do! result = [] for brain in self.__catalog(p_criteria): obj = brain.getObject() if not obj is None: result.append(obj) return result regards Max M -- hilsen/regards Max M, Denmark http://www.mxm.dk/ IT's Mad Science
Max M wrote:
You should at least check that getObject() does not return a None object. Which it can *very* easily do!
Eh? That only happens if you're careless enough to delete an object without uncataloging it... Chris -- Simplistix - Content Management, Zope & Python Consulting - http://www.simplistix.co.uk
Max M wrote at 2004-3-16 18:50 +0100:
... This approach should be failsafe
result = [] for brain in brains: try: obj = brain.getObject() result.append(obj) except: # Will probably raise AttributeError on None object pass
You are proposing here a so called "bare" "try ... except". Such "try ... except"s are wide spread in the Zope sources. They have been the cause of many many difficult to analyse problems. Therefore, they are considered bad. The best approach is not to catch exceptions at all (and handle them in your "standard_error_message"). When you know that some exceptions are not real exceptions you can catch *precisely* these exceptions. There are really few occasions where you can be sure that *any* exception is not a real exception... -- Dieter
Dieter Maurer wrote:
Max M wrote at 2004-3-16 18:50 +0100:
try: obj = brain.getObject() result.append(obj) except: # Will probably raise AttributeError on None object pass
You are proposing here a so called "bare" "try ... except".
Such "try ... except"s are wide spread in the Zope sources. They have been the cause of many many difficult to analyse problems. Therefore, they are considered bad.
I know, that was why I added the comment. So that the corrects exception could be catched. But I was to lazy to do it correctly, as it wasn't in code i was going to use myself. -- hilsen/regards Max M, Denmark http://www.mxm.dk/ IT's Mad Science
participants (5)
-
Andre Meyer -
Chris Withers -
Dieter Maurer -
Dragos Chirila -
Max M