예제 #1
0
 class ComponentB(Component):
     mp_extension_point = MultiProductExtensionPoint(ITest)
예제 #2
0
파일: api.py 프로젝트: tsanov/bloodhound
class BloodhoundSearchApi(Component):
    """Implements core indexing functionality, provides methods for
    searching, adding and deleting documents from index.
    """
    implements(IEnvironmentSetupParticipant, ISupportMultiProductEnvironment)

    def __init__(self, *args, **kwargs):
        import pkg_resources
        locale_dir = pkg_resources.resource_filename(__name__, 'locale')
        add_domain(self.env.path, locale_dir)
        super(BloodhoundSearchApi, self).__init__(*args, **kwargs)

    backend = ExtensionOption(
        'bhsearch',
        'search_backend',
        ISearchBackend,
        'WhooshBackend',
        'Name of the component implementing Bloodhound Search backend \
        interface: ISearchBackend.',
        doc_domain='bhsearch')

    parser = ExtensionOption(
        'bhsearch',
        'query_parser',
        IQueryParser,
        'DefaultQueryParser',
        'Name of the component implementing Bloodhound Search query \
        parser.',
        doc_domain='bhsearch')

    index_pre_processors = OrderedExtensionsOption(
        'bhsearch',
        'index_preprocessors',
        IDocIndexPreprocessor,
        ['SecurityPreprocessor'],
        include_missing=True,
    )
    result_post_processors = ExtensionPoint(IResultPostprocessor)
    query_processors = ExtensionPoint(IQueryPreprocessor)

    index_participants = MultiProductExtensionPoint(IIndexParticipant)

    def query(self,
              query,
              sort=None,
              fields=None,
              filter=None,
              facets=None,
              pagenum=1,
              pagelen=20,
              highlight=False,
              highlight_fields=None,
              context=None):
        """Return query result from an underlying search backend.

        Arguments:
        :param query: query string e.g. “bla status:closed” or a parsed
            representation of the query.
        :param sort: optional sorting
        :param boost: optional list of fields with boost values e.g.
            {“id”: 1000, “subject” :100, “description”:10}.
        :param filter: optional list of terms. Usually can be cached by
            underlying search framework. For example {“type”: “wiki”}
        :param facets: optional list of facet terms, can be field or expression
        :param page: paging support
        :param pagelen: paging support
        :param highlight: highlight matched terms in fields
        :param highlight_fields: list of fields to highlight
        :param context: request context

        :return: result QueryResult
        """
        # pylint: disable=too-many-locals
        self.env.log.debug("Receive query request: %s", locals())

        parsed_query = self.parser.parse(query, context)

        parsed_filters = self.parser.parse_filters(filter)
        # TODO: add query parsers and meta keywords post-parsing

        # TODO: apply security filters

        query_parameters = dict(
            query=parsed_query,
            query_string=query,
            sort=sort,
            fields=fields,
            filter=parsed_filters,
            facets=facets,
            pagenum=pagenum,
            pagelen=pagelen,
            highlight=highlight,
            highlight_fields=highlight_fields,
        )
        for query_processor in self.query_processors:
            query_processor.query_pre_process(query_parameters, context)

        query_result = self.backend.query(**query_parameters)

        for post_processor in self.result_post_processors:
            post_processor.post_process(query_result)

        query_result.debug["api_parameters"] = query_parameters
        return query_result

    def start_operation(self):
        return self.backend.start_operation()

    def rebuild_index(self):
        """Rebuild underlying index"""
        self.log.info('Rebuilding the search index.')
        self.backend.recreate_index()
        with self.backend.start_operation() as operation_context:
            doc = None
            try:
                for participant in self.index_participants:
                    self.log.info(
                        "Reindexing resources provided by %s in product %s" %
                        (participant.__class__.__name__,
                         getattr(participant.env.product, 'name', "''")))
                    docs = participant.get_entries_for_index()
                    for doc in docs:
                        self.log.debug("Indexing document %s:%s/%s" % (
                            doc.get('product'),
                            doc['type'],
                            doc['id'],
                        ))
                        self.add_doc(doc, operation_context)
                self.log.info("Reindexing complete.")
            except Exception, ex:
                self.log.error(ex)
                if doc:
                    self.log.error("Doc that triggers the error: %s" % doc)
                raise