Browse Source

[search] Add Hit Count facet

Romain Rigaux 11 years ago
parent
commit
64ec8013be

+ 6 - 2
apps/search/src/search/api.py

@@ -100,13 +100,17 @@ class SolrApi(object):
         ('start', solr_query['start']),
     )
 
-    if collection['facets']:
+    if any(collection['facets']):
       params += (
         ('facet', 'true'),
         ('facet.mincount', 0),
         ('facet.limit', 10),
       )
-      params += tuple([('facet.field', '{!ex=%s}%s' % (facet['field'], facet['field'])) for facet in collection['facets']])
+      for facet in collection['facets']:
+        if facet['type'] == 'query':
+          params += (('facet.query', '%s' % facet['field']),)
+        elif facet['type'] == 'field':
+          params += (('facet.field', '{!ex=%s}%s' % (facet['field'], facet['field'])),)
 
     fqs = solr_query['fq']
     for fq, val in fqs.iteritems():

+ 27 - 17
apps/search/src/search/models.py

@@ -305,16 +305,13 @@ class Collection(models.Model):
       "fieldsSelected": [field['name'] for field in fields],
     }
     
-    FACETS = {
-      "dates": [], "fields": [],
-      "charts": [], "properties": {"sort": "count", "mincount": 1, "isEnabled": True, "limit": 10, 'schemd_id_field': 'id'}, "ranges": [], "order": []
-    };  
-    
+    FACETS = []
+
     collection_properties = {
       'id': self.id, 'name': self.name, 'label': self.label,
-      'template': TEMPLATE, 'facets': FACETS['fields'], 
+      'template': TEMPLATE, 'facets': FACETS, 
       'fields': fields, 'idField': id_field, 
-    };      
+    }      
     
     return collection_properties
 
@@ -397,8 +394,8 @@ def get_facet_field_format(field, type, facets):
     pass
   return format
 
-def get_facet_field(field, facets):
-  facets = filter(lambda facet: facet['type'] == 'field' and facet['field'] == field, facets)
+def get_facet_field(category, field, facets):
+  facets = filter(lambda facet: facet['type'] == category and facet['field'] == field, facets)
   if facets:
     return facets[0]
   else:
@@ -468,18 +465,31 @@ def augment_solr_response2(response, collection, solr_query):
   fq = solr_query['fq']
 
   if response and response.get('facet_counts'):
+    category = 'field'
     if response['facet_counts']['facet_fields']:
-      for cat in response['facet_counts']['facet_fields']:
-        selected_field = fq.get(cat, '')
-        collection_facet = get_facet_field(cat, collection['facets'])
+      for name in response['facet_counts']['facet_fields']:
+        selected_field = fq.get(name, '')
+        collection_facet = get_facet_field(category, name, collection['facets'])
         facet = {
           'id': collection_facet['id'],
-          'field': cat,
-          'type': 'field',
-          'label': get_facet_field_label(cat, collection['facets']),
-          'counts': pairwise2(cat, selected_field, response['facet_counts']['facet_fields'][cat]),
+          'field': name,
+          'type': category,
+          'label': collection_facet['label'],
+          'counts': pairwise2(name, selected_field, response['facet_counts']['facet_fields'][name]),
         }
         normalized_facets.append(facet)
+    if response['facet_counts']['facet_queries']:
+      category = 'query'
+      for name, value in response['facet_counts']['facet_queries'].iteritems():
+        collection_facet = get_facet_field(category, name, collection['facets'])
+        facet = {
+          'id': collection_facet['id'],
+          'query': name,
+          'type': category,
+          'label': name,
+          'count': value,
+        }        
+        normalized_facets.append(facet)
 
   # TODO HTML escape docs!
   
@@ -516,7 +526,7 @@ def augment_solr_exception(response, collection, solr_query):
         "type": facet['type'],
         "label": facet['label']
       }
-      for facet in collection['facets']
+      for categories in collection['facets'].values() for facet in categories
     ],
     "responseHeader": {
       "status": -1,

+ 26 - 5
apps/search/src/search/templates/search2.mako

@@ -193,7 +193,7 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
     <div class="draggable-widget" data-bind="draggable: draggableResultset" title="${_('Results')}" rel="tooltip" data-placement="top"><a href="#"><i class="fa fa-table"></i></a></div>    
     <div class="draggable-widget" data-bind="draggable: draggableFacet" title="${_('Text Facet')}" rel="tooltip" data-placement="top"><a href="#"><i class="fa fa-sort-amount-asc"></i></a></div>    
     <div class="draggable-widget" data-bind="draggable: draggablePie" title="${_('Pie Chart')}" rel="tooltip" data-placement="top"><a href="#"><i class="hcha hcha-pie-chart"></i></a></div>
-    <div class="draggable-widget" data-bind="draggable: draggableMap" title="${_('Count')}" rel="tooltip" data-placement="top"><a href="#"><i class="fa fa-tachometer"></i></a></div>
+    <div class="draggable-widget" data-bind="draggable: draggableHit" title="${_('Hit Count')}" rel="tooltip" data-placement="top"><a href="#"><i class="fa fa-tachometer"></i></a></div>
     <div class="draggable-widget" data-bind="draggable: draggableArea" title="${_('Line Chart')}" rel="tooltip" data-placement="top"><a href="#"><i class="hcha hcha-area-chart"></i></a></div>
     <div class="draggable-widget" data-bind="draggable: draggableBar" title="${_('Timeline')}" rel="tooltip" data-placement="top"><a href="#"><i class="hcha hcha-bar-chart"></i></a></div>
     <div class="draggable-widget" data-bind="draggable: draggableLine" title="${_('Filter Bar')}" rel="tooltip" data-placement="top"><a href="#"><i class="fa fa-filter"></i></a></div>
@@ -297,6 +297,25 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   This is an empty widget.
 </script>
 
+
+<script type="text/html" id="hit-widget">
+  <!-- ko ifnot: $root.getFacetFromQuery(id) -->
+    <a data-bind="click: showAddFacetModal" class="btn" href="javascript:void(0)"><i class="fa fa-plus"></i></a>
+  <!-- /ko -->
+
+  <!-- ko if: $root.getFacetFromQuery(id) -->
+  <div class="row-fluid" data-bind="with: $root.getFacetFromQuery(id)">
+    <div data-bind="visible: $root.isEditing, with: $root.collection.getFacetById($parent.id())" style="margin-bottom: 20px">      
+      ${ _('Label') }: <input type="text" data-bind="value: label" />
+      <br/>      
+      ${ _('Field') }: <input type="text" data-bind="value: field" />
+    </div>  
+
+    ${ _('Hits') }: <span data-bind="text: count" />
+  </div>
+  <!-- /ko -->
+</script>
+
 <script type="text/html" id="facet-widget">
   <!-- ko ifnot: $root.getFacetFromQuery(id) -->
     <a data-bind="click: showAddFacetModal" class="btn" href="javascript:void(0)"><i class="fa fa-plus"></i></a>
@@ -461,6 +480,7 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
         <div class="input-append">
           <input id="facetName" type="text">
           <input id="widgetId" type="hidden">
+          <input id="widgetType" type="hidden">
         </div>
       </div>
     </p>
@@ -523,9 +543,9 @@ $(document).ready(function () {
       read: target,
       write: function (newValue) {
         var current = target(),
-                roundingMultiplier = Math.pow(10, precision),
-                newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
-                valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
+          roundingMultiplier = Math.pow(10, precision),
+          newValueAsNum = isNaN(newValue) ? 0 : parseFloat(+newValue),
+          valueToWrite = Math.round(newValueAsNum * roundingMultiplier) / roundingMultiplier;
 
         if (valueToWrite !== current) {
           target(valueToWrite);
@@ -561,11 +581,12 @@ $(document).ready(function () {
 
   function showAddFacetModal(widget) {
     $("#widgetId").val(widget.id());
+    $("#widgetType").val(widget.widgetType());        
     $("#addFacetModal").modal("show");
   };
 
   function submitAddFacetModal() {
-    viewModel.collection.addFacet({'name': $("#facetName").val(), 'widget_id': $("#widgetId").val()});
+    viewModel.collection.addFacet({'name': $("#facetName").val(), 'widget_id': $("#widgetId").val(), 'widgetType': $("#widgetType").val()});
     $('#addFacetModal').modal("hide");
     viewModel.search();
   };

+ 1 - 0
apps/search/src/search/views.py

@@ -141,6 +141,7 @@ def save(request):
     # Todo update certain atttributes like, label, enabled...
     hue_collection.save()
     response['status'] = 0
+    response['id'] = hue_collection.id
     response['message'] = _('Page saved !')
   else:
     response['message'] = _('There is no collection to search.')

+ 16 - 9
apps/search/static/js/search.ko.js

@@ -226,28 +226,32 @@ var Collection = function (vm, collection) {
   self.fields = ko.mapping.fromJS(collection.fields);
 
   self.addFacet = function (facet_json) {
+	var facetType = facet_json.widgetType == 'hit-widget' ? 'query' : 'field';
+
     self.facets.push(ko.mapping.fromJS({
       "id": facet_json.widget_id,
       "label": facet_json.name,
       "field": facet_json.name,
-      "type": "field"
+      "type": facetType
     }));
-  }
+  };
 
   self.removeFacet = function (widget_id) {
-    $.each(self.facets(), function (index, item) {
-      if (item.id() == widget_id()) {
-        self.facets.remove(item);
+    $.each(self.facets(), function (index, facet) {	
+      if (facet.id() == widget_id()) {
+        self.facets.remove(facet);
+        return false;
       }
     });
   }  
   
   self.getFacetById = function (facet_id) {
     var _facet = null;
-    $.each(self.facets(), function (index, facet) {
+    $.each(self.facets(), function (index, facet) {//alert(ko.mapping.toJSON(category));
       if (facet.id() == facet_id) {
         _facet = facet;
-      }      
+        return false;
+      }
     });
     return _facet;
   }  
@@ -258,6 +262,7 @@ var Collection = function (vm, collection) {
       var position = self.template.fieldsSelected.indexOf(field.name());
       if (position != -1) {
     	_fields[position] = field;
+    	return false;
       }      
     });
     return _fields;
@@ -324,7 +329,8 @@ var SearchViewModel = function (collection_json, query_json) {
     self.isEditing(!self.isEditing());
   };
   self.isRetrievingResults = ko.observable(false);
-    
+      
+  self.draggableHit = ko.observable(new Widget(12, UUID(), "Hit Count", "hit-widget"));
   self.draggableFacet = ko.observable(new Widget(12, UUID(), "Facet", "facet-widget"));
   self.draggableResultset = ko.observable(new Widget(12, UUID(), "Results", "resultset-widget"));
   self.draggableBar = ko.observable(new Widget(12, UUID(), "Bar Chart", "bar-widget"));
@@ -361,7 +367,7 @@ var SearchViewModel = function (collection_json, query_json) {
             var fields = self.collection.template.fieldsSelected();
             // Field selection or whole record
             if (fields.length != 0) {
-              $.each(self.collection.template.fieldsSelected(), function (index, field) {//alert(ko.mapping.toJSON(field));  
+              $.each(self.collection.template.fieldsSelected(), function (index, field) {  
                 row.push(item[field]);
               });
             } else {
@@ -396,6 +402,7 @@ var SearchViewModel = function (collection_json, query_json) {
       layout: ko.mapping.toJSON(self.columns)
     },function (data) {
       if (data.status == 0) {
+    	collection.id(data.id);
         $(document).trigger("info", data.message);
       }
       else {