class ComponentB(Component): mp_extension_point = MultiProductExtensionPoint(ITest)
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