diff --git a/views.py b/views.py index 153925ddddc282528cf4285b2d775218872feca5_dmlld3MucHk=..e0a9244f7ebb07367f002e2747f7031494806840_dmlld3MucHk= 100644 --- a/views.py +++ b/views.py @@ -19,6 +19,8 @@ from elasticsearch import Elasticsearch from elasticsearch.exceptions import NotFoundError from elasticsearch_dsl import Search +from elasticsearch_dsl.connections import connections +from elasticsearch_dsl import FacetedSearch, TermsFacet, DateHistogramFacet from bs4 import BeautifulSoup from logilab.mtconverter import xml_escape @@ -27,8 +29,44 @@ from cubes.elasticsearch.es import indexable_types +def get_connection(config): + try: + connections.get_connection() + except KeyError: + locations = config['elasticsearch-locations'] + index_name = config['index-name'] + # TODO sanitize locations + connections.create_connection(hosts=locations.split(','), + index=index_name, + timeout=20) + +class CWFacetedSearch(FacetedSearch): + #doc_types = ['NewsContent', 'CommemorationItem', 'Circular',] + # fields that should be searched + fields = ["title^3", "name^3", "content^2", 'content', '_all',] + + facets = { + # use bucket aggregations to define facets + 'cw_etype': TermsFacet(field='cw_etype'), + 'creation_date': DateHistogramFacet(field='creation_date', interval='month'), + 'commemoration_year': DateHistogramFacet(field='commemoration_year', interval='year'), + 'year': DateHistogramFacet(field='year', interval='year'), + } + def __init__(self, query=None, filters={}, doc_types=None): + if doc_types: + self.doc_types = doc_types + super(CWFacetedSearch, self).__init__(query, filters) + + def highlight(self, search): + """ + Add custom highlighting + """ + return search.highlight(*self.fields) \ + .highlight_options(pre_tags="", + post_tags="", + fragment_size=150) class ElasticSearchView(StartupView): __regid__ = "esearch" def call(self, **kwargs): @@ -30,8 +68,9 @@ class ElasticSearchView(StartupView): __regid__ = "esearch" def call(self, **kwargs): + # TODO if no ES configuration, redirect or display warning search_comp = self._cw.vreg['components'].select_or_none('search-comp', self._cw) if search_comp: @@ -40,26 +79,12 @@ 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) + get_connection(self._cw.vreg.config) + search = CWFacetedSearch(query_string, + doc_types = indexable_types(self._cw.vreg.schema)) try: response = search.execute() except NotFoundError: self.w(u'index not found in elasticsearch') return self.w(u'Resultats: %s' % response.hits.total) @@ -60,9 +85,14 @@ try: response = search.execute() except NotFoundError: self.w(u'index not found in elasticsearch') return self.w(u'Resultats: %s' % response.hits.total) + self.display_facets(response) + self.display_results(response) + + def display_results(self, response): + self.w(u'<div id="main-center" class="col-xs-10" role="main">') self.w(u'<ul>') for result in response: self.w(u'<li>') @@ -84,3 +114,22 @@ pass self.w(u'</li>') self.w(u'</ul>') + self.w(u'</div>') + + + def display_facets(self, response): + self.w(u'''<aside id="aside-main-left" class="col-xs-2 cwjs-aside"> + <div class="panel panel-default contextFreeBox facet_filterbox"> + <div class="panel-heading"> + <div class="panel-title">facettes</div> + </div> + ''') + for attribute in ('cw_etype', 'creation_date'): + self.w(u'<div class="facetBody vocabularyFacet">') + self.w(u'<div class="facetTitle">{}</div>'.format(attribute)) + for (tag, count, selected) in response.facets[attribute]: + # facetValueSelected / facetValueDisabled in class + facet_item = u'<div class="facetValue facetCheckBox"><span>{} {} {}</span></div>' + self.w(facet_item.format(tag, ' (SELECTED):' if selected else ':', count)) + self.w(u'</div>') + self.w(u'</div></aside>')