# -*- coding: utf-8 -*- # copyright 2016 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr -- mailto:contact@logilab.fr # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 2.1 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. """elasticsearch search views""" from elasticsearch import Elasticsearch from elasticsearch.exceptions import NotFoundError from elasticsearch_dsl import Search from bs4 import BeautifulSoup from logilab.mtconverter import xml_escape from cubicweb.view import StartupView from cubes.elasticsearch.es import indexable_types class ElasticSearchView(StartupView): __regid__ = "esearch" def call(self, **kwargs): search_comp = self._cw.vreg['components'].select_or_none('search-comp', self._cw) if search_comp: search_comp.render(w=self.w) self.w(u'<h1>%s</h1>' % self._cw._('Recherche')) query_string = xml_escape(self._cw.form.get('search', '')) self.w(u'<h2>Résultats pour : <em>%s</em></h2>' % query_string) locations = self._cw.vreg.config['elasticsearch-locations'] index_name = self._cw.vreg.config['index-name'] # TODO sanitize locations # TODO create a es objet/connexion outside of each request and reuse it if locations: es = Elasticsearch(locations.split(',')) else: es = Elasticsearch() search = Search(using=es, index=index_name, doc_type=indexable_types(self._cw.vreg.schema)) \ .query('multi_match', # noqa query=query_string, fields=("title^3", "name^3", "content^2", "_all",)) \ .highlight('content') \ .highlight_options(pre_tags="", post_tags="", fragment_size=150) try: response = search.execute() except NotFoundError: self.w(u'index not found in elasticsearch') return self.w(u'Resultats: %s' % response.hits.total) self.w(u'<ul>') for result in response: self.w(u'<li>') infos = result.to_dict() infos['_score'] = result.meta.score infos['keys'] = result.to_dict().keys() infos.setdefault('title', infos.get('name', infos.get('reference', u'n/a'))) try: self.w(u'<a href="%(cwuri)s">%(title)s</a> (%(_score).2f)<br/>' % (infos)) if self._cw.form.get('debug-es'): self.w(u' [%(keys)s] <br/>' % infos) except KeyError: self.w(u'Missing key in : %s' % infos.keys()) try: for fragment in result.meta.highlight.content: self.w(u'... %s' % BeautifulSoup(fragment, 'lxml').get_text()) self.w(u' ... <br/>') except AttributeError: pass self.w(u'</li>') self.w(u'</ul>')