浏览代码

[search] Text, pie and bar facets can also be ranges

Romain Rigaux 11 年之前
父节点
当前提交
6da1259

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

@@ -109,9 +109,9 @@ class SolrApi(object):
       for facet in collection['facets']:
         if facet['type'] == 'query':
           params += (('facet.query', '%s' % facet['field']),)
-        if facet['type'] == 'range':
+        elif facet['type'] == 'range':
           params += tuple([
-             ('facet.range', facet['field']),
+             ('facet.range', '{!ex=%s}%s' % (facet['field'], facet['field'])),
              ('f.%s.facet.range.start' % facet['field'], facet['properties']['start']),
              ('f.%s.facet.range.end' % facet['field'], facet['properties']['end']),
              ('f.%s.facet.range.gap' % facet['field'], facet['properties']['gap']),]

+ 7 - 11
apps/search/src/search/models.py

@@ -304,7 +304,7 @@ class Collection(models.Model):
       "isGridLayout": True,
       "showFieldList": True,
       "fieldsAttributes": [{'name': field['name'], 'sort': {'direction': None}} for field in fields], # sort priority, asc/desc/none
-      "fieldsSelected": [field['name'] for field in fields],
+      "fieldsSelected": [],
     }
     
     FACETS = []
@@ -404,12 +404,6 @@ def get_facet_field(category, field, facets):
   else:
     return None
 
-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:
-    return None
 
 def get_facet_field_label(field, facets):
   label = field
@@ -478,8 +472,6 @@ def augment_solr_response2(response, collection, solr_query):
     # [{u'field': u'sun', u'type': u'query', u'id': u'67b43a63-ed22-747b-47e8-b31aad1431ea', u'label': u'sun'}
     for facet in collection['facets']:
       category = facet['type']
-      if category == 'pie-widget': # could be facet_range
-        category = 'field'
       
       if category == 'field' and response['facet_counts']['facet_fields']:
         for name in response['facet_counts']['facet_fields']: # todo get from the list
@@ -496,13 +488,17 @@ def augment_solr_response2(response, collection, solr_query):
           normalized_facets.append(facet)
       elif category == 'range' and response['facet_counts']['facet_ranges']:
           name = facet['field']
-          collection_facet = get_facet_field(category, name, collection['facets'])          
+          collection_facet = get_facet_field(category, name, collection['facets'])
+          counts = response['facet_counts']['facet_ranges'][name]['counts']
+          if facet['widgetType'] == 'facet-widget':
+            selected_field = fq.get(name, '') # todo with multi filter
+            counts = pairwise2(name, selected_field, counts)
           facet = {
             'id': collection_facet['id'],
             'field': name,
             'type': category,
             'label': collection_facet['label'],
-            'counts': response['facet_counts']['facet_ranges'][name]['counts'],
+            'counts': counts,
           }
           normalized_facets.append(facet)
       elif category == 'query' and response['facet_counts']['facet_queries']:

+ 10 - 4
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: 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: 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: draggableBar" title="${_('Bar Chart')}" rel="tooltip" data-placement="top"><a href="#"><i class="hcha hcha-bar-chart"></i></a></div>
     <div class="draggable-widget" data-bind="draggable: draggableHistogram" title="${_('Timeline')}" rel="tooltip" data-placement="top"><a href="#"><i class="fa fa-long-arrow-right"></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>
@@ -325,8 +325,12 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   <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" />
+      <br/>
+      ${ _('Range') }: <input type="checkbox" data-bind="checked: isRange" />
+      <a href="javascript: void(0)" class="btn"><i class="fa fa-sort-alpha-asc"></i></a>
+      <a href="javascript: void(0)" class="btn"><i class="fa fa-sort-numeric-asc"></i></a>
+      <a href="javascript: void(0)" class="btn"><i class="fa fa-sort-numeric-desc"></i></a>
     </div>  
 
     <div data-bind="text: label" style="font-weight: bold"></div>
@@ -470,9 +474,10 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   <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" />
       <br/>
+      ${ _('Range') }: <input type="checkbox" data-bind="checked: isRange" />      
+      <br/>
       ${ _('Start') }: <input type="text" data-bind="value: properties.start" />
       ${ _('End') }: <input type="text" data-bind="value: properties.end" />
       ${ _('Gap') }: <input type="text" data-bind="value: properties.gap" />
@@ -495,8 +500,9 @@ ${ commonheader(_('Search'), "search", user, "60px") | n,unicode }
   <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" />
+      <br/>
+      ${ _('Range') }: <input type="checkbox" data-bind="checked: isRange" />      
     </div>  
 
     <div data-bind="pieChart: {data: counts, transformer: pieChartDataTransformer, onClick: function(d){viewModel.query.selectFacet(d.data.obj)}}" />

+ 37 - 23
apps/search/src/search/views.py

@@ -478,36 +478,33 @@ def new_facet(request, collection_id):
   result = {'status': -1, 'message': 'Error'}
   
   try:
-    collection = json.loads(request.POST.get('collection', '{}')) # TODO perms decorator
+    collection = json.loads(request.POST.get('collection', '{}'))
     
     facet_id = request.POST['id']
     facet_label = request.POST['label']
     facet_field = request.POST['field']
     widget_type = request.POST['widget_type']
     properties = {}
-    
-    if widget_type == 'hit-widget':
-      facet_type = 'query'
-    elif widget_type == 'histogram-widget':
-      facet_type = 'range'
-    elif widget_type == 'bar-widget':
-      facet_type = 'range'
-    else:
-      facet_type = 'field'      
+    is_range = False
 
-    if facet_type == 'range':
-      SLOTS = 50            
-      
+    try:
+      SLOTS = 50
       stats_json = SolrApi(SOLR_URL.get(), request.user).stats(collection['name'], [facet_field])
+      stat_facet = stats_json['stats']['stats_fields'][facet_field]
       
-      if isinstance(stats_json['stats']['stats_fields'][facet_field]['min'], numbers.Number):
-        stats_min = int(stats_json['stats']['stats_fields'][facet_field]['min']) # if field is int, cast as int
-        stats_max = int(stats_json['stats']['stats_fields'][facet_field]['max'])
+      if isinstance(stat_facet['min'], numbers.Number):
+        stats_min = int(stat_facet['min']) # if field is float, cast as float isinstance(y, float)
+        stats_max = int(stat_facet['max'])
         gap = (stats_max - stats_min) / SLOTS
-      else:
-        stats_min = stats_json['stats']['stats_fields'][facet_field]['min']
-        stats_max = stats_json['stats']['stats_fields'][facet_field]['max']
-        difference = (mktime(datetime.strptime(stats_max, '%Y-%m-%dT%H:%M:%SZ').timetuple()) - mktime(datetime.strptime(stats_min, '%Y-%m-%dT%H:%M:%SZ').timetuple())) / SLOTS
+        if gap < 1:
+          gap = 1
+        is_range = True
+      elif 'T' in stat_facet['min']:
+        stats_min = stat_facet['min']
+        stats_max = stat_facet['max']
+        difference = (
+            mktime(datetime.strptime(stats_max, '%Y-%m-%dT%H:%M:%SZ').timetuple()) - 
+            mktime(datetime.strptime(stats_min, '%Y-%m-%dT%H:%M:%SZ').timetuple())) / SLOTS
   
         if difference < 1:
           unit = 'SECONDS'
@@ -519,14 +516,29 @@ def new_facet(request, collection_id):
           unit = 'DAYS'
         else:
           unit = 'MONTHS'
-  
         gap = '+1' + unit      
-
+        is_range = True
+    except Exception, e:
+      # stats not supported on all the fields, like text
+      pass
+                
+    if is_range:
+      facet_type = 'range'
       properties = {
         'start': stats_min,
         'end': stats_max,
         'gap': gap,
-      }
+      }       
+#    elif widget_type == 'hit-widget':
+#      facet_type = 'query'
+#    elif widget_type == 'histogram-widget':
+#      facet_type = 'range'
+#    elif widget_type == 'bar-widget':
+#      facet_type = 'range'
+#    elif widget_type == 'pie-widget':
+#      facet_type = 'range'      
+    else:
+      facet_type = 'field'        
         
     result['message'] = ''
     result['facet'] = {
@@ -534,6 +546,8 @@ def new_facet(request, collection_id):
       'label': facet_label,
       'field': facet_field,
       'type': facet_type,
+      'widgetType': widget_type,
+      'isRange': is_range,
       'properties': properties
     }
     result['status'] = 0

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

@@ -239,16 +239,19 @@ var Collection = function (vm, collection) {
         "field": facet_json.name,
         "widget_type": facet_json.widgetType
       }, function (data) {
-      if (data.status == 0) {
-	    var facet = ko.mapping.fromJS(data.facet);
-	    facet.field.subscribe(function () {
+        if (data.status == 0) {
+	      var facet = ko.mapping.fromJS(data.facet);
+	      facet.field.subscribe(function () {
+	        vm.search();
+	      });
+	      facet.isRange.subscribe(function () {
+	        vm.search();
+	      });	    
+	      self.facets.push(facet);
 	      vm.search();
-	    });
-	    self.facets.push(facet);
-	    vm.search();
-      } else {
-         $(document).trigger("error", data.message);
-      }
+        } else {
+          $(document).trigger("error", data.message);
+        }
     }).fail(function (xhr, textStatus, errorThrown) {});
   };