querySrv.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. define([
  2. 'angular',
  3. 'underscore',
  4. 'config',
  5. 'kbn'
  6. ],
  7. function (angular, _, config, kbn) {
  8. 'use strict';
  9. var module = angular.module('kibana.services');
  10. module.service('querySrv', function(dashboard, ejsResource, filterSrv, $q) {
  11. // Create an object to hold our service state on the dashboard
  12. dashboard.current.services.query = dashboard.current.services.query || {};
  13. _.defaults(dashboard.current.services.query,{
  14. idQueue : [],
  15. list : {},
  16. ids : [],
  17. });
  18. this.colors = [
  19. "#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1
  20. "#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2
  21. "#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3
  22. "#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", //4
  23. "#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", //5
  24. "#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", //6
  25. "#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7
  26. ];
  27. // For convenience
  28. var ejs = ejsResource(config.elasticsearch);
  29. var _q = dashboard.current.services.query;
  30. // Holds all actual queries, including all resolved abstract queries
  31. var resolvedQueries = [];
  32. // Defaults for generic query object
  33. var _query = {
  34. alias: '',
  35. pin: false,
  36. type: 'lucene',
  37. enable: true
  38. };
  39. // Defaults for specific query types
  40. var _dTypes = {
  41. "lucene": {
  42. query: "*"
  43. },
  44. "regex": {
  45. query: ".*"
  46. },
  47. "topN": {
  48. query: "*",
  49. field: "_type",
  50. size: 5,
  51. union: 'AND'
  52. }
  53. };
  54. // query type meta data that is not stored on the dashboard object
  55. this.queryTypes = {
  56. lucene: {
  57. require:">=0.17.0",
  58. icon: "icon-circle",
  59. resolve: function(query) {
  60. // Simply returns itself
  61. var p = $q.defer();
  62. p.resolve(_.extend(query,{parent:query.id}));
  63. return p.promise;
  64. }
  65. },
  66. regex: {
  67. require:">=0.90.3",
  68. icon: "icon-circle",
  69. resolve: function(query) {
  70. // Simply returns itself
  71. var p = $q.defer();
  72. p.resolve(_.extend(query,{parent:query.id}));
  73. return p.promise;
  74. }
  75. },
  76. topN : {
  77. require:">=0.90.3",
  78. icon: "icon-cog",
  79. resolve: function(q) {
  80. var suffix = '';
  81. if (q.union === 'AND') {
  82. suffix = ' AND (' + (q.query||'*') + ')';
  83. } else if (q.union === 'OR') {
  84. suffix = ' OR (' + (q.query||'*') + ')';
  85. }
  86. var request = ejs.Request().indices(dashboard.indices);
  87. // Terms mode
  88. request = request
  89. .facet(ejs.TermsFacet('query')
  90. .field(q.field)
  91. .size(q.size)
  92. .facetFilter(ejs.QueryFilter(
  93. ejs.FilteredQuery(
  94. ejs.QueryStringQuery(q.query || '*'),
  95. filterSrv.getBoolFilter(filterSrv.ids)
  96. )))).size(0);
  97. var results = request.doSearch();
  98. // Like the regex and lucene queries, this returns a promise
  99. return results.then(function(data) {
  100. var _colors = kbn.colorSteps(q.color,data.facets.query.terms.length);
  101. var i = -1;
  102. return _.map(data.facets.query.terms,function(t) {
  103. ++i;
  104. return self.defaults({
  105. query : q.field+':"'+kbn.addslashes(t.term)+'"'+suffix,
  106. alias : t.term + (q.alias ? " ("+q.alias+")" : ""),
  107. type : 'lucene',
  108. color : _colors[i],
  109. parent : q.id
  110. });
  111. });
  112. });
  113. }
  114. }
  115. };
  116. // Save a reference to this
  117. var self = this;
  118. this.init = function() {
  119. self.list = dashboard.current.services.query.list;
  120. self.ids = dashboard.current.services.query.ids;
  121. // Check each query object, populate its defaults
  122. _.each(self.list,function(query) {
  123. query = self.defaults(query);
  124. });
  125. if (self.ids.length === 0) {
  126. self.set({});
  127. }
  128. };
  129. // This is used both for adding queries and modifying them. If an id is passed,
  130. // the query at that id is updated
  131. this.set = function(query,id) {
  132. if(!_.isUndefined(id)) {
  133. if(!_.isUndefined(self.list[id])) {
  134. _.extend(self.list[id],query);
  135. return id;
  136. } else {
  137. return false;
  138. }
  139. } else {
  140. // Query must have an id and color already
  141. query.id = _.isUndefined(query.id) ? nextId() : query.id;
  142. query.color = query.color || colorAt(query.id);
  143. // Then it can get defaults
  144. query = self.defaults(query);
  145. self.list[query.id] = query;
  146. self.ids.push(query.id);
  147. return query.id;
  148. }
  149. };
  150. this.defaults = function(query) {
  151. _.defaults(query,_query);
  152. _.defaults(query,_dTypes[query.type]);
  153. query.color = query.color || colorAt(query.id);
  154. return query;
  155. };
  156. this.remove = function(id) {
  157. if(!_.isUndefined(self.list[id])) {
  158. delete self.list[id];
  159. // This must happen on the full path also since _.without returns a copy
  160. self.ids = dashboard.current.services.query.ids = _.without(self.ids,id);
  161. _q.idQueue.unshift(id);
  162. _q.idQueue.sort(function(v,k){
  163. return v-k;
  164. });
  165. return true;
  166. } else {
  167. return false;
  168. }
  169. };
  170. // These are the only query types that can be returned by a compound query.
  171. this.toEjsObj = function (q) {
  172. switch(q.type)
  173. {
  174. case 'lucene':
  175. return ejs.QueryStringQuery(q.query || '*');
  176. case 'regex':
  177. return ejs.RegexpQuery('_all',q.query);
  178. default:
  179. return false;
  180. }
  181. };
  182. //
  183. this.getQueryObjs = function(ids) {
  184. if(_.isUndefined(ids)) {
  185. return resolvedQueries;
  186. } else {
  187. return _.flatten(_.map(ids,function(id) {
  188. return _.where(resolvedQueries,{parent:id});
  189. }));
  190. }
  191. };
  192. // BROKEN
  193. this.idsByMode = function(config) {
  194. switch(config.mode)
  195. {
  196. case 'all':
  197. return _.pluck(_.where(self.list,{enable:true}),'id');
  198. case 'pinned':
  199. return _.pluck(_.where(self.list,{pin:true,enable:true}),'id');
  200. case 'unpinned':
  201. return _.pluck(_.where(self.list,{pin:false,enable:true}),'id');
  202. case 'selected':
  203. return _.intersection(_.pluck(_.where(self.list,{enable:true}),'id'),config.ids);
  204. default:
  205. return _.pluck(_.where(self.list,{enable:true}),'id');
  206. }
  207. };
  208. // This populates the internal query list and returns a promise containing it
  209. this.resolve = function() {
  210. // Find ids of all abstract queries
  211. // Get a list of resolvable ids, constrast with total list to get abstract ones
  212. return $q.all(_.map(self.ids,function(q) {
  213. return self.queryTypes[self.list[q].type].resolve(_.clone(self.list[q])).then(function(data){
  214. return data;
  215. });
  216. })).then(function(data) {
  217. resolvedQueries = _.flatten(data);
  218. _.each(resolvedQueries,function(q,i) {
  219. q.id = i;
  220. });
  221. return resolvedQueries;
  222. });
  223. };
  224. var nextId = function() {
  225. if(_q.idQueue.length > 0) {
  226. return _q.idQueue.shift();
  227. } else {
  228. return self.ids.length;
  229. }
  230. };
  231. var colorAt = function(id) {
  232. return self.colors[id % self.colors.length];
  233. };
  234. self.init();
  235. });
  236. });