=========
Searching
=========


Introduction
------------
Grok supports the vanilla indexing services available in Zope 3 straight out of the box. Catalog uses developer defined indexes for searching. In other words, you have to define the indexes you want to use to search you objects before you perform the actual search.

* Field: search matching an entire field
* Set: search for keywords in a field
* Text: full-text searching

The module that provides a catalog is zope.app.catalog. Catalog is a utility that contains indexes and can perform searches.


Example: BookShelf
------------------
We will use an example application to demonstrate how to register indexes and perform searches on zope.app.catalog. The code can be downloaded here: http://paleosoft.googlecode.com/svn/bookshelf/.

Is this example we have a Shelf that can contain many books. The books are a simple model composed only by title.

Before we can search anything, we need to add some data: for this task, we will demonstrate how to use XMLRPC in Grok.


XML-RPC in Grok: Adding and retrieving data remotely
----------------------------------------------------
XML-RPC is a remote procedure call protocol encoded in XML that uses HTTP as the transport layer. You can call remote methods and other callable structures just like a local call.

To serve the contents of a Model via XMLRPC you need to create a subclass of grok.XMLRPC. The example below shows how to do that.

::

    class Shelf(grok.Container):
        pass

    class ShelfRPC(grok.XMLRPC):
        def list(self):
            return list(self.context.keys())

        def add(self, book_dict):
            shelf = self.context
            book = Book(**book_dict) # see book.py
            name = INameChooser(shelf).chooseName(book_dict.get('title'), book) # see shelf.py
            shelf[name] = book
            return name

And thats it. You now have a complete list of the items contained on shelf and can add some items (books, in this case) to shelf. Here is how you can access these methods over the web.

::

    >>> import xmlrpclib
    >>> server = xmlrpclib.ServerProxy("http://localhost:8080/bookshelf/shelf") # Use your app URL
    >>> server.add({'title':'Test one'})
    'Test one'
    >>> server.add({'title':'Test two'})
    'Test two'
    >>> server.list()
    ['Test one', 'Test two']


ME GROK SEARCH THE DATA!
------------------------
Expain how to search using zope.app.catalog.

::

    import grok
    from zope.app.catalog.interfaces import ICatalog
    from zope.component import getUtility
    from operator import attrgetter
    from shelf import Shelf
    
    class Index(grok.View):
        grok.context(Shelf)
        def update(self, query=None):
            if not query:
                results = self.context.values()
            else:
                catalog = getUtility(ICatalog)
                results = catalog.searchResults(title=query)
                # Note: to sort the results, we must cast the result iterable
                # to a list, which can be very expensive
                results = list(results)
            self.results = sorted(results, key=attrgetter('title'))


Other ways to perform queries
-----------------------------
Explain hurry.query and its strenghs (using code from grok/doc/minitutorials/searching.txt).