From 18451e5ed8e1021b5d860897facb22b23e06935a Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Fri, 3 Feb 2017 10:44:00 -0700 Subject: [PATCH] Improve highlighting by using highlight_query with all_fields enabled (#9671) * Add all_fields to highlight query to improve highlighting * Refactor highlighting and move out of _flatten * Make changes as per @bargs' requests * Add documentation about highlightAll setting * Fix docs typo * Remove unused function * Remove unused code --- docs/management/advanced-options.asciidoc | 4 +- .../public/discover/controllers/discover.js | 19 ++--- .../public/courier/data_source/_abstract.js | 17 +++- .../courier/data_source/search_source.js | 5 +- .../public/highlight/__tests__/highlight.js | 73 ----------------- .../highlight/__tests__/highlight_html.js | 69 ++++++++++++++++ .../highlight/__tests__/highlight_request.js | 82 +++++++++++++++++++ src/ui/public/highlight/highlight.js | 36 ++------ src/ui/public/highlight/highlight_html.js | 29 +++++++ src/ui/public/highlight/highlight_request.js | 44 ++++++++++ src/ui/public/highlight/highlight_tags.js | 7 +- src/ui/public/highlight/html_tags.js | 5 ++ .../_field_format/content_types.js | 6 +- src/ui/public/stringify/types/url.js | 6 +- src/ui/settings/defaults.js | 5 ++ 15 files changed, 273 insertions(+), 134 deletions(-) delete mode 100644 src/ui/public/highlight/__tests__/highlight.js create mode 100644 src/ui/public/highlight/__tests__/highlight_html.js create mode 100644 src/ui/public/highlight/__tests__/highlight_request.js create mode 100644 src/ui/public/highlight/highlight_html.js create mode 100644 src/ui/public/highlight/highlight_request.js create mode 100644 src/ui/public/highlight/html_tags.js diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index 01c0d6def71fa1..0c748cb86a8707 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -35,6 +35,8 @@ document. `discover:sampleSize`:: The number of rows to show in the Discover table. `doc_table:highlight`:: Highlight results in Discover and Saved Searches Dashboard. Highlighting makes request slow when working on big documents. Set this property to `false` to disable highlighting. +`doc_table:highlight:all_fields`:: Improves highlighting by using a separate `highlight_query` that uses `all_fields` mode on +`query_string` queries. Set to `false` if you are using a `default_field` in your index. `courier:maxSegmentCount`:: Kibana splits requests in the Discover app into segments to limit the size of requests sent to the Elasticsearch cluster. This setting constrains the length of the segment list. Long segment lists can significantly increase request processing time. @@ -86,4 +88,4 @@ Markdown. `timelion:default_rows`:: The default number of rows to use on a timelion sheet. `timelion:graphite.url`:: [experimental] Used with graphite queries, this it the URL of your host `timelion:quandl.key`:: [experimental] Used with quandl queries, this is your API key from www.quandl.com -`state:storeInSessionStorage`:: [experimental] Kibana tracks UI state in the URL, which can lead to problems when there is a lot of information there and the URL gets very long. Enabling this will store parts of the state in your browser session instead, to keep the URL shorter. \ No newline at end of file +`state:storeInSessionStorage`:: [experimental] Kibana tracks UI state in the URL, which can lead to problems when there is a lot of information there and the URL gets very long. Enabling this will store parts of the state in your browser session instead, to keep the URL shorter. diff --git a/src/core_plugins/kibana/public/discover/controllers/discover.js b/src/core_plugins/kibana/public/discover/controllers/discover.js index 2010edfe8dd16e..65320bc511e5a6 100644 --- a/src/core_plugins/kibana/public/discover/controllers/discover.js +++ b/src/core_plugins/kibana/public/discover/controllers/discover.js @@ -13,7 +13,6 @@ import 'ui/courier'; import 'ui/index_patterns'; import 'ui/state_management/app_state'; import 'ui/timefilter'; -import 'ui/highlight/highlight_tags'; import 'ui/share'; import VisProvider from 'ui/vis'; import DocTitleProvider from 'ui/doc_title'; @@ -89,7 +88,7 @@ app.directive('discoverApp', function () { }); function discoverController($scope, config, courier, $route, $window, Notifier, - AppState, timefilter, Promise, Private, kbnUrl, highlightTags) { + AppState, timefilter, Promise, Private, kbnUrl) { const Vis = Private(VisProvider); const docTitle = Private(DocTitleProvider); @@ -143,7 +142,9 @@ function discoverController($scope, config, courier, $route, $window, Notifier, // the actual courier.SearchSource $scope.searchSource = savedSearch.searchSource; $scope.indexPattern = resolveIndexPatternLoading(); - $scope.searchSource.set('index', $scope.indexPattern); + $scope.searchSource + .set('index', $scope.indexPattern) + .highlightAll(true); if (savedSearch.id) { docTitle.change(savedSearch.title); @@ -475,22 +476,12 @@ function discoverController($scope, config, courier, $route, $window, Notifier, kbnUrl.change('/discover'); }; - $scope.updateDataSource = Promise.method(function () { + $scope.updateDataSource = Promise.method(function updateDataSource() { $scope.searchSource .size($scope.opts.sampleSize) .sort(getSort($state.sort, $scope.indexPattern)) .query(!$state.query ? null : $state.query) .set('filter', queryFilter.getFilters()); - - if (config.get('doc_table:highlight')) { - $scope.searchSource.highlight({ - pre_tags: [highlightTags.pre], - post_tags: [highlightTags.post], - fields: {'*': {}}, - require_field_match: false, - fragment_size: 2147483647 // Limit of an integer. - }); - } }); // TODO: On array fields, negating does not negate the combination, rather all terms diff --git a/src/ui/public/courier/data_source/_abstract.js b/src/ui/public/courier/data_source/_abstract.js index 0b6832f876ebe3..72ffcc9eff4427 100644 --- a/src/ui/public/courier/data_source/_abstract.js +++ b/src/ui/public/courier/data_source/_abstract.js @@ -8,12 +8,14 @@ import ErrorHandlersProvider from '../_error_handlers'; import FetchProvider from '../fetch'; import DecorateQueryProvider from './_decorate_query'; import FieldWildcardProvider from '../../field_wildcard'; +import { getHighlightRequestProvider } from '../../highlight'; export default function SourceAbstractFactory(Private, Promise, PromiseEmitter) { - let requestQueue = Private(RequestQueueProvider); - let errorHandlers = Private(ErrorHandlersProvider); - let courierFetch = Private(FetchProvider); - let { fieldWildcardFilter } = Private(FieldWildcardProvider); + const requestQueue = Private(RequestQueueProvider); + const errorHandlers = Private(ErrorHandlersProvider); + const courierFetch = Private(FetchProvider); + const { fieldWildcardFilter } = Private(FieldWildcardProvider); + const getHighlightRequest = Private(getHighlightRequestProvider); function SourceAbstract(initialState, strategy) { let self = this; @@ -371,6 +373,13 @@ export default function SourceAbstractFactory(Private, Promise, PromiseEmitter) delete flatState.filters; } + if (flatState.highlightAll != null) { + if (flatState.highlightAll && flatState.body.query) { + flatState.body.highlight = getHighlightRequest(flatState.body.query); + } + delete flatState.highlightAll; + } + // re-write filters within filter aggregations (function recurse(aggBranch) { if (!aggBranch) return; diff --git a/src/ui/public/courier/data_source/search_source.js b/src/ui/public/courier/data_source/search_source.js index f4279aee4940d0..cbee633a0238f9 100644 --- a/src/ui/public/courier/data_source/search_source.js +++ b/src/ui/public/courier/data_source/search_source.js @@ -93,6 +93,7 @@ export default function SearchSourceFactory(Promise, Private, config) { 'filter', 'sort', 'highlight', + 'highlightAll', 'aggs', 'from', 'size', @@ -178,7 +179,6 @@ export default function SearchSourceFactory(Promise, Private, config) { }); }; - /****** * PRIVATE APIS ******/ @@ -249,6 +249,7 @@ export default function SearchSourceFactory(Promise, Private, config) { case 'index': case 'type': case 'id': + case 'highlightAll': if (key && state[key] == null) { state[key] = val; } @@ -273,7 +274,7 @@ export default function SearchSourceFactory(Promise, Private, config) { // ignore if we already have a value if (state.body[key] == null) { if (key === 'query' && _.isString(val)) { - val = { query_string: { query: val }}; + val = { query_string: { query: val } }; } state.body[key] = val; diff --git a/src/ui/public/highlight/__tests__/highlight.js b/src/ui/public/highlight/__tests__/highlight.js deleted file mode 100644 index 050cd99d92c27a..00000000000000 --- a/src/ui/public/highlight/__tests__/highlight.js +++ /dev/null @@ -1,73 +0,0 @@ -import angular from 'angular'; -import expect from 'expect.js'; -import ngMock from 'ng_mock'; -import 'ui/highlight'; - -describe('Highlight', function () { - - let filter; - - let tags; - - beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function (highlightFilter, highlightTags) { - filter = highlightFilter; - tags = highlightTags; - })); - - let text = '' + - 'Bacon ipsum dolor amet pork loin pork cow pig beef chuck ground round shankle sirloin landjaeger kevin ' + - 'venison sausage ribeye tongue. Chicken bacon ball tip pork. Brisket pork capicola spare ribs pastrami rump ' + - 'sirloin, t-bone ham shoulder jerky turducken bresaola. Chicken cow beef picanha. Picanha hamburger alcatra ' + - 'cupim. Salami capicola boudin pork belly shank picanha.'; - - it('should not modify text if highlight is empty', function () { - expect(filter(text, undefined)).to.be(text); - expect(filter(text, null)).to.be(text); - expect(filter(text, [])).to.be(text); - }); - - it('should highlight a single result', function () { - let highlights = [ - tags.pre + 'hamburger' + tags.post + ' alcatra cupim. Salami capicola boudin pork belly shank picanha.' - ]; - let result = filter(text, highlights); - expect(result.indexOf('hamburger')).to.be.greaterThan(-1); - expect(result.split('hamburger').length).to.be(text.split('hamburger').length); - }); - - it('should highlight multiple results', function () { - let highlights = [ - 'kevin venison sausage ribeye tongue. ' + tags.pre + 'Chicken' + tags.post + ' bacon ball tip pork. Brisket ' + - 'pork capicola spare ribs pastrami rump sirloin, t-bone ham shoulder jerky turducken bresaola. ' + tags.pre + - 'Chicken' + tags.post + ' cow beef picanha. Picanha' - ]; - let result = filter(text, highlights); - expect(result.indexOf('Chicken')).to.be.greaterThan(-1); - expect(result.split('Chicken').length).to.be(text.split('Chicken').length); - }); - - it('should highlight multiple hits in a result', function () { - let highlights = [ - 'Bacon ipsum dolor amet ' + tags.pre + 'pork' + tags.post + ' loin ' + - '' + tags.pre + 'pork' + tags.post + ' cow pig beef chuck ground round shankle ' + - 'sirloin landjaeger', - 'kevin venison sausage ribeye tongue. Chicken bacon ball tip ' + - '' + tags.pre + 'pork' + tags.post + '. Brisket ' + - '' + tags.pre + 'pork' + tags.post + ' capicola spare ribs', - 'hamburger alcatra cupim. Salami capicola boudin ' + tags.pre + 'pork' + tags.post + ' ' + - 'belly shank picanha.' - ]; - let result = filter(text, highlights); - expect(result.indexOf('pork')).to.be.greaterThan(-1); - expect(result.split('pork').length).to.be(text.split('pork').length); - }); - - it('should accept an object and return a string containing its properties', function () { - let obj = {foo: 1, bar: 2}; - let result = filter(obj, null); - expect(result.indexOf('' + obj)).to.be(-1); - expect(result.indexOf('foo')).to.be.greaterThan(-1); - expect(result.indexOf('bar')).to.be.greaterThan(-1); - }); -}); diff --git a/src/ui/public/highlight/__tests__/highlight_html.js b/src/ui/public/highlight/__tests__/highlight_html.js new file mode 100644 index 00000000000000..db562e7fa93b19 --- /dev/null +++ b/src/ui/public/highlight/__tests__/highlight_html.js @@ -0,0 +1,69 @@ +import expect from 'expect.js'; +import highlightTags from '../highlight_tags'; +import htmlTags from '../html_tags'; +import getHighlightHtml from '../highlight_html'; + +describe('getHighlightHtml', function () { + const text = '' + + 'Bacon ipsum dolor amet pork loin pork cow pig beef chuck ground round shankle sirloin landjaeger kevin ' + + 'venison sausage ribeye tongue. Chicken bacon ball tip pork. Brisket pork capicola spare ribs pastrami rump ' + + 'sirloin, t-bone ham shoulder jerky turducken bresaola. Chicken cow beef picanha. Picanha hamburger alcatra ' + + 'cupim. Salami capicola boudin pork belly shank picanha.'; + + it('should not modify text if highlight is empty', function () { + expect(getHighlightHtml(text, undefined)).to.be(text); + expect(getHighlightHtml(text, null)).to.be(text); + expect(getHighlightHtml(text, [])).to.be(text); + }); + + it('should preserve escaped text', function () { + const highlights = ['']; + const result = getHighlightHtml('<foo>', highlights); + expect(result.indexOf('')).to.be(-1); + expect(result.indexOf('<foo>')).to.be.greaterThan(-1); + }); + + it('should highlight a single result', function () { + const highlights = [ + highlightTags.pre + 'hamburger' + highlightTags.post + ' alcatra cupim. Salami capicola boudin pork belly shank picanha.' + ]; + const result = getHighlightHtml(text, highlights); + expect(result.indexOf(htmlTags.pre + 'hamburger' + htmlTags.post)).to.be.greaterThan(-1); + expect(result.split(htmlTags.pre + 'hamburger' + htmlTags.post).length).to.be(text.split('hamburger').length); + }); + + it('should highlight multiple results', function () { + const highlights = [ + 'kevin venison sausage ribeye tongue. ' + highlightTags.pre + 'Chicken' + highlightTags.post + ' bacon ball tip pork. Brisket ' + + 'pork capicola spare ribs pastrami rump sirloin, t-bone ham shoulder jerky turducken bresaola. ' + highlightTags.pre + + 'Chicken' + highlightTags.post + ' cow beef picanha. Picanha' + ]; + const result = getHighlightHtml(text, highlights); + expect(result.indexOf(htmlTags.pre + 'Chicken' + htmlTags.post)).to.be.greaterThan(-1); + expect(result.split(htmlTags.pre + 'Chicken' + htmlTags.post).length).to.be(text.split('Chicken').length); + }); + + it('should highlight multiple hits in a result', function () { + const highlights = [ + 'Bacon ipsum dolor amet ' + highlightTags.pre + 'pork' + highlightTags.post + ' loin ' + + '' + highlightTags.pre + 'pork' + highlightTags.post + ' cow pig beef chuck ground round shankle ' + + 'sirloin landjaeger', + 'kevin venison sausage ribeye tongue. Chicken bacon ball tip ' + + '' + highlightTags.pre + 'pork' + highlightTags.post + '. Brisket ' + + '' + highlightTags.pre + 'pork' + highlightTags.post + ' capicola spare ribs', + 'hamburger alcatra cupim. Salami capicola boudin ' + highlightTags.pre + 'pork' + highlightTags.post + ' ' + + 'belly shank picanha.' + ]; + const result = getHighlightHtml(text, highlights); + expect(result.indexOf(htmlTags.pre + 'pork' + htmlTags.post)).to.be.greaterThan(-1); + expect(result.split(htmlTags.pre + 'pork' + htmlTags.post).length).to.be(text.split('pork').length); + }); + + it('should accept an object and return a string containing its properties', function () { + const obj = { foo: 1, bar: 2 }; + const result = getHighlightHtml(obj, null); + expect(result.indexOf('' + obj)).to.be(-1); + expect(result.indexOf('foo')).to.be.greaterThan(-1); + expect(result.indexOf('bar')).to.be.greaterThan(-1); + }); +}); diff --git a/src/ui/public/highlight/__tests__/highlight_request.js b/src/ui/public/highlight/__tests__/highlight_request.js new file mode 100644 index 00000000000000..4011f495bc8ca3 --- /dev/null +++ b/src/ui/public/highlight/__tests__/highlight_request.js @@ -0,0 +1,82 @@ +import expect from 'expect.js'; +import ngMock from 'ng_mock'; +import getHighlightRequestProvider from '../highlight_request'; + +describe('getHighlightRequest', () => { + const queryStringQuery = { query_string: { query: 'foo' } }; + const rangeQuery = { range: { '@timestamp': { gte: 0, lte: 0 } } }; + const boolQueryWithSingleCondition = { + bool: { + must: queryStringQuery, + } + }; + const boolQueryWithMultipleConditions = { + bool: { + must: [ + queryStringQuery, + rangeQuery + ] + } + }; + + let config; + let previousHighlightConfig; + let previousAllFieldsConfig; + let getHighlightRequest; + + beforeEach(ngMock.module('kibana')); + beforeEach(ngMock.inject(function (_config_) { + config = _config_; + previousHighlightConfig = config.get('doc_table:highlight'); + previousAllFieldsConfig = config.get('doc_table:highlight:all_fields'); + })); + + afterEach(() => { + config.set('doc_table:highlight', previousHighlightConfig); + config.set('doc_table:highlight:all_fields', previousAllFieldsConfig); + }); + + it('should be a function', () => { + getHighlightRequest = getHighlightRequestProvider(config); + expect(getHighlightRequest).to.be.a(Function); + }); + + it('should add the all_fields param with query_string query without modifying original query', () => { + getHighlightRequest = getHighlightRequestProvider(config); + const request = getHighlightRequest(queryStringQuery); + expect(request.fields['*']).to.have.property('highlight_query'); + expect(request.fields['*'].highlight_query.query_string).to.have.property('all_fields'); + expect(queryStringQuery.query_string).to.not.have.property('all_fields'); + }); + + it('should add the all_fields param with bool query with single condition without modifying original query', () => { + getHighlightRequest = getHighlightRequestProvider(config); + const request = getHighlightRequest(boolQueryWithSingleCondition); + expect(request.fields['*']).to.have.property('highlight_query'); + expect(request.fields['*'].highlight_query.bool.must.query_string).to.have.property('all_fields'); + expect(queryStringQuery.query_string).to.not.have.property('all_fields'); + }); + + it('should add the all_fields param with bool query with multiple conditions without modifying original query', () => { + getHighlightRequest = getHighlightRequestProvider(config); + const request = getHighlightRequest(boolQueryWithMultipleConditions); + expect(request.fields['*']).to.have.property('highlight_query'); + expect(request.fields['*'].highlight_query.bool.must).to.have.length(boolQueryWithMultipleConditions.bool.must.length); + expect(request.fields['*'].highlight_query.bool.must[0].query_string).to.have.property('all_fields'); + expect(queryStringQuery.query_string).to.not.have.property('all_fields'); + }); + + it('should return undefined if highlighting is turned off', () => { + config.set('doc_table:highlight', false); + getHighlightRequest = getHighlightRequestProvider(config); + const request = getHighlightRequest(queryStringQuery); + expect(request).to.be(undefined); + }); + + it('should not add the highlight_query param if all_fields is turned off', () => { + config.set('doc_table:highlight:all_fields', false); + getHighlightRequest = getHighlightRequestProvider(config); + const request = getHighlightRequest(queryStringQuery); + expect(request.fields['*']).to.not.have.property('highlight_query'); + }); +}); diff --git a/src/ui/public/highlight/highlight.js b/src/ui/public/highlight/highlight.js index f51a3ae2bfb528..30d5e89d9113a6 100644 --- a/src/ui/public/highlight/highlight.js +++ b/src/ui/public/highlight/highlight.js @@ -1,31 +1,7 @@ -import 'ui/highlight/highlight_tags'; -import _ from 'lodash'; -import angular from 'angular'; -import uiModules from 'ui/modules'; +import getHighlightHtml from './highlight_html'; +import getHighlightRequestProvider from './highlight_request'; -let module = uiModules.get('kibana'); - -module.filter('highlight', function (highlightTags) { - return function (formatted, highlight) { - if (typeof formatted === 'object') formatted = angular.toJson(formatted); - - _.each(highlight, function (section) { - section = _.escape(section); - - // Strip out the highlight tags to compare against the formatted string - let untagged = section - .split(highlightTags.pre).join('') - .split(highlightTags.post).join(''); - - // Replace all highlight tags with proper html tags - let tagged = section - .split(highlightTags.pre).join('') - .split(highlightTags.post).join(''); - - // Replace all instances of the untagged string with the properly tagged string - formatted = formatted.split(untagged).join(tagged); - }); - - return formatted; - }; -}); +export default { + getHighlightHtml, + getHighlightRequestProvider +}; diff --git a/src/ui/public/highlight/highlight_html.js b/src/ui/public/highlight/highlight_html.js new file mode 100644 index 00000000000000..413c290872cce6 --- /dev/null +++ b/src/ui/public/highlight/highlight_html.js @@ -0,0 +1,29 @@ +import _ from 'lodash'; +import angular from 'angular'; +import highlightTags from './highlight_tags'; +import htmlTags from './html_tags'; + +export default function getHighlightHtml(fieldValue, highlights) { + let highlightHtml = (typeof fieldValue === 'object') + ? angular.toJson(fieldValue) + : fieldValue; + + _.each(highlights, function (highlight) { + const escapedHighlight = _.escape(highlight); + + // Strip out the highlight tags to compare against the field text + const untaggedHighlight = escapedHighlight + .split(highlightTags.pre).join('') + .split(highlightTags.post).join(''); + + // Replace all highlight tags with proper html tags + const taggedHighlight = escapedHighlight + .split(highlightTags.pre).join(htmlTags.pre) + .split(highlightTags.post).join(htmlTags.post); + + // Replace all instances of the untagged string with the properly tagged string + highlightHtml = highlightHtml.split(untaggedHighlight).join(taggedHighlight); + }); + + return highlightHtml; +} diff --git a/src/ui/public/highlight/highlight_request.js b/src/ui/public/highlight/highlight_request.js new file mode 100644 index 00000000000000..dda1ca2383ff43 --- /dev/null +++ b/src/ui/public/highlight/highlight_request.js @@ -0,0 +1,44 @@ +import _ from 'lodash'; +import highlightTags from './highlight_tags'; + +const FRAGMENT_SIZE = Math.pow(2, 31) - 1; // Max allowed value for fragment_size (limit of a java int) + +/** + * Returns a clone of the query with `"all_fields": true` set on any `query_string` queries + */ +function getHighlightQuery(query) { + const clone = _.cloneDeep(query); + + if (_.has(clone, 'query_string')) { + clone.query_string.all_fields = true; + } else if (_.has(clone, 'bool.must')) { + if (Array.isArray(clone.bool.must)) { + clone.bool.must = clone.bool.must.map(getHighlightQuery); + } else { + clone.bool.must = getHighlightQuery(clone.bool.must); + } + } + + return clone; +} + +export default function getHighlightRequestProvider(config) { + if (!config.get('doc_table:highlight')) { + return _.noop; + } + + return function getHighlightRequest(query) { + const fieldsParams = config.get('doc_table:highlight:all_fields') + ? { highlight_query: getHighlightQuery(query) } + : {}; + + return { + pre_tags: [highlightTags.pre], + post_tags: [highlightTags.post], + fields: { + '*': fieldsParams + }, + fragment_size: FRAGMENT_SIZE + }; + }; +} diff --git a/src/ui/public/highlight/highlight_tags.js b/src/ui/public/highlight/highlight_tags.js index 350357ec35b592..edf473391e3035 100644 --- a/src/ui/public/highlight/highlight_tags.js +++ b/src/ui/public/highlight/highlight_tags.js @@ -1,10 +1,7 @@ -import uiModules from 'ui/modules'; -let module = uiModules.get('kibana'); - // By default, ElasticSearch surrounds matched values in . This is not ideal because it is possible that // the value could contain in the value. We define these custom tags that we would never expect to see // inside a field value. -module.constant('highlightTags', { +export default { pre: '@kibana-highlighted-field@', post: '@/kibana-highlighted-field@' -}); +}; diff --git a/src/ui/public/highlight/html_tags.js b/src/ui/public/highlight/html_tags.js new file mode 100644 index 00000000000000..7cf2ac89540eb2 --- /dev/null +++ b/src/ui/public/highlight/html_tags.js @@ -0,0 +1,5 @@ +// These are the html tags that will replace the highlight tags. +export default { + pre: '', + post: '' +}; diff --git a/src/ui/public/index_patterns/_field_format/content_types.js b/src/ui/public/index_patterns/_field_format/content_types.js index ed82f0210c1f0e..d5545c0e6645da 100644 --- a/src/ui/public/index_patterns/_field_format/content_types.js +++ b/src/ui/public/index_patterns/_field_format/content_types.js @@ -1,7 +1,7 @@ import _ from 'lodash'; import angular from 'angular'; -import 'ui/highlight'; -export default function contentTypesProvider(highlightFilter) { +import { getHighlightHtml } from 'ui/highlight'; +export default function contentTypesProvider() { let types = { html: function (format, convert) { @@ -47,7 +47,7 @@ export default function contentTypesProvider(highlightFilter) { if (!hit || !hit.highlight || !hit.highlight[field.name]) { return formatted; } else { - return highlightFilter(formatted, hit.highlight[field.name]); + return getHighlightHtml(formatted, hit.highlight[field.name]); } } diff --git a/src/ui/public/stringify/types/url.js b/src/ui/public/stringify/types/url.js index eb1c46aeaaafe3..339aaa4d39fae3 100644 --- a/src/ui/public/stringify/types/url.js +++ b/src/ui/public/stringify/types/url.js @@ -3,7 +3,9 @@ import 'ui/field_format_editor/pattern/pattern'; import 'ui/stringify/icons'; import IndexPatternsFieldFormatProvider from 'ui/index_patterns/_field_format/field_format'; import urlTemplate from 'ui/stringify/editors/url.html'; -export default function UrlFormatProvider(Private, highlightFilter) { +import { getHighlightHtml } from 'ui/highlight'; + +export default function UrlFormatProvider(Private) { let FieldFormat = Private(IndexPatternsFieldFormatProvider); @@ -94,7 +96,7 @@ export default function UrlFormatProvider(Private, highlightFilter) { return '' + label + ''; default: if (hit && hit.highlight && hit.highlight[field.name]) { - label = highlightFilter(label, hit.highlight[field.name]); + label = getHighlightHtml(label, hit.highlight[field.name]); } return '' + label + ''; diff --git a/src/ui/settings/defaults.js b/src/ui/settings/defaults.js index 4a8ac5a2953256..2f1368d79a50a9 100644 --- a/src/ui/settings/defaults.js +++ b/src/ui/settings/defaults.js @@ -75,6 +75,11 @@ export default function defaultSettingsProvider() { description: 'Highlight results in Discover and Saved Searches Dashboard.' + 'Highlighting makes requests slow when working on big documents.', }, + 'doc_table:highlight:all_fields': { + value: true, + description: 'Improves highlighting by using a separate "highlight_query" that uses "all_fields" mode on "query_string" queries. ' + + 'Set to false if you are using a "default_field" in your index.', + }, 'courier:maxSegmentCount': { value: 30, description: 'Requests in discover are split into segments to prevent massive requests from being sent to ' +