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>')