Search Services

Contents

1. Overview
2. Enable/Disable a search service
3. Build a custom search service
3.1 Search service specifications/requirements
3.1.1 3.1.1 Using SearchService base class
3.1.2 3.1.2 Using ListLinksService class
3.1.3 3.1.3 Using KnowledgeBaseService class
3.2 Good practices

1. Overview

Search services are meant to display information contextual to a search query in very specialized way, in the sense that they can search/retrieve/display data beyond the traditional concept of records. Typical search services could for example include:

Search services are displayed (in addition) just before the results returned by the standard Invenio search engine. Each service is queried with the context, and returns:

The relevance returned by the service is typically a score between 0 and 100 (see websearch_services.CFG_WEBSEARCH_SERVICE_MAX_SERVICE_ANSWER_RELEVANCE for details) which indicate how much the service thinks it can address the "question" and how much it thinks it was able to answer it. Given the wanted simplistic (non-scientific) nature of services it is extremely important to consider the score very carefully, and compare it with existing services when designing a new service. Failing to do so might lead to hide more relevant answers provided by other services with non-relevant information.

Services are designed to provide unobtrusive and useful information to the user. To that end some measure are taken to cut possible verbosity introduced by the services:

See also the section 3.2 Good practices.

2. Enable/Disable a search service

In order to enable a service, drop its files into the following location:

/opt/invenio/lib/python/invenio/search_services/

To disable a service, remove the file from the above directory.

3. Build a custom search service

Services use the Invenio plugin_utils infrastructure, and are self-contained in single Pythonic files that comply with the specifications defined in section 3.1 Search service specifications/requirements.

3.1 Search service specifications/requirements

A search service is a Pythonic file stored in /opt/invenio/lib/python/invenio/search_services/, which name corresponds to a class defined in the file.

In order to be valid, your service should inherit from the base SearchService class and implement some functions (see Section 3.1.1 Using SearchService base class). Other helper, more specialized classes exists to help you build services that responds with links of links (Section 3.1.2 Using ListLinksService class) or answer based on a BibKnowledge knowledge base (3.1.3 Using KnowledgeBaseService class)

3.1.1 Using SearchService base class

Start implementing your service by defining a class that inherits from the SearchService base class. Choose a class name that matches the name of your service file.

For eg. a spellchecker service could exist in /opt/invenio/lib/python/invenio/search_services/SpellCheckerService.py, with the following content:

from invenio.websearch.websearch_services import SearchService

__plugin_version__ = "Search Service Plugin API 1.0"

class CollectionNameSearchService(SearchService):

    def get_description(self, ln=CFG_SITE_LANG):
        "Return service description"
        return "Spell check user input"


    def answer(self, req, user_info, of, cc, colls_to_search, p, f, search_units, ln):
        """
        Answer question given by context.

        Return (relevance, html_string) where relevance is integer
        from 0 to 100 indicating how relevant to the question the
        answer is (see C{CFG_WEBSEARCH_SERVICE_MAX_SERVICE_ANSWER_RELEVANCE} for details) ,
        and html_string being a formatted answer.
        """

        [...]

        return (score, html_answer)

The bare minimum for a search service to be valid is to inherit from the abstract base class "SearchService". The service must:

If your service must pre-process some data and cache it, it can override the following helper methods:

3.1.2 Using ListLinksService class

If your service is designed to display list of responses, you can inherit from the ListLinksService class instead of SearchService, in order to benefit from the following additional helper functions:

from invenio.websearch.websearch_services import ListLinksService
from invenio.miscutil.messages import gettext_set_language

__plugin_version__ = "Search Service Plugin API 1.0"

class CollectionNameSearchService(ListLinksService):

   [...]

   def get_description(self, ln=CFG_SITE_LANG):
        "Return service description"
        return "A foo that answer with list of bars"


   def get_label(self, ln=CFG_SITE_LANG):
        """
        Return label displayed next to the service responses.

        @rtype: string
        """

        _ = gettext_set_language(ln)
        return _("You might be interested in")


    def answer(self, req, user_info, of, cc, colls_to_search, p, f, search_units, ln):
        """
        Answer question given by context.

        Return (relevance, html_string) where relevance is integer
        from 0 to 100 indicating how relevant to the question the
        answer is (see C{CFG_WEBSEARCH_SERVICE_MAX_SERVICE_ANSWER_RELEVANCE} for details) ,
        and html_string being a formatted answer.
        """

        [...]

        return (score, self.display_answer_helper(list_of_tuples_labels_urls))

The requirements from the base class SearchService are still valid when using ListLinksService:

3.1.3 Using KnowledgeBaseService class

If you would like to build a service that answers automatically based on the values stored in a BibKnowledge knowledge base, use the KnowledgeBaseService. In this case you do not need to define the answer(..) function, which is already implemented for you:

from invenio.websearch.websearch_services import KnowledgeBaseService
from invenio.miscutil.messages import gettext_set_language

__plugin_version__ = "Search Service Plugin API 1.0"

class MyKBService(KnowledgeBaseService):

   [...]
   def get_description(self, ln=CFG_SITE_LANG):
        "Return service description"
        return "A foo that answer with list of bars, based on myKB"


   def get_label(self, ln=CFG_SITE_LANG):
        """
        Return label displayed next to the service responses.

        @rtype: string
        """
        _ = gettext_set_language(ln)
        return _("You might be interested in")


    def get_kbname(self):
        "Load knowledge base with this name"
        return "myKB"

With the above code, the knowledge base "myKB" will be loaded and used to reply to the user. It is expected that the knowledge base contains for each mapping a list of whitespace-separated as key, and a label + url (separated with a "|") as value. For eg:


help submit thesis   ->     How to submit a thesis|http://localhost/help/how-to-submit-thesis
Atlantis Times       ->     Atlantis Times journal|http://localhost/journal/AtlantisTimes

When filling up the knowledge base keys, one should carefully select the keywords in order to focus on a very specific subject, and avoid too generic terms that would unnecessarily match too many user queries. One should also consider the possible clash with other services (the first rule of the above KB example might for example hide responses from the "SubmissionNameSearchService" service

A default implementation of a KnowledgeBaseService is provided with Invenio: "FAQKBService". This service makes use of the demo knowledge base named "FAQ".

3.2 Good practices

See also 1. Overview section.