Do not match exclusion on meta/scripted fields. Disable filter bar when on 'Filter fields' tab. Removed exclusion checkbox in the field controls page. Corrected typos. Improved documentation phrasing.

This commit is contained in:
Stéphane Campinas 2016-06-09 09:14:12 +01:00
parent 4be31b2878
commit 79e87ca3ae
12 changed files with 63 additions and 83 deletions

View file

@ -32,7 +32,7 @@
</div>
<form role="form">
<input aria-label="Filter" ng-model="fieldFilter" class="form-control span12" type="text" placeholder="Filter" />
<input ng-disabled="state.tab == 'fieldFilters'" aria-label="Filter" ng-model="fieldFilter" class="form-control span12" type="text" placeholder="Filter" />
</form>
<br />

View file

@ -5,13 +5,14 @@ import typeHtml from 'plugins/kibana/settings/sections/indices/_field_type.html'
import controlsHtml from 'plugins/kibana/settings/sections/indices/_field_controls.html';
import uiModules from 'ui/modules';
import indexedFieldsTemplate from 'plugins/kibana/settings/sections/indices/_indexed_fields.html';
import { fieldWildcardMatcher } from 'ui/field_wildcard';
import FieldWildcardProvider from 'ui/field_wildcard';
uiModules.get('apps/settings')
.directive('settingsIndicesIndexedFields', function ($filter) {
.directive('settingsIndicesIndexedFields', function (Private, $filter) {
const yesTemplate = '<i class="fa fa-check" aria-label="yes"></i>';
const noTemplate = '';
const filter = $filter('filter');
const { fieldWildcardMatcher } = Private(FieldWildcardProvider);
return {
restrict: 'E',
@ -42,7 +43,7 @@ uiModules.get('apps/settings')
const childScope = _.assign($scope.$new(), { field: field });
rowScopes.push(childScope);
const excluded = field.exclude || fieldWildcardMatch(field.name);
const excluded = fieldWildcardMatch(field.name);
return [
{

View file

@ -1,7 +1,7 @@
<h3>Field Filters</h3>
<p>
Field filters can be used to exclude one or more fields when fetching the document source. This happens in apps like Discover for the doc table. Each row is built using the source of a single document, and if you have documents with large or unimportant fields you may benefit from filtering those out at this lowere level.
Field filters can be used to exclude one or more fields when fetching the document source. This happens when viewing a document in the Discover app, or with a table displaying results from a saved search in the Dashboard app. Each row is built using the source of a single document, and if you have documents with large or unimportant fields you may benefit from filtering those out at this lower level.
</p>
<div ng-class="{ saving: fieldFilters.saving }" class="field-filters-container">
@ -22,7 +22,7 @@
ng-model="filter.value"
input-focus
ng-if="fieldFilters.editting === filter"
placeholder="field name filter, accepts wildcards (i.e. `user:*`)"
placeholder="field name filter, accepts wildcards (e.g., `user*` to filter fields starting with 'user')"
type="text"
required
class="form-control">
@ -63,7 +63,7 @@
<div class="input-group">
<input
ng-model="fieldFilters.newValue"
placeholder="field name filter, accepts wildcards (i.e. `user:*`)"
placeholder="field name filter, accepts wildcards (e.g., `user*` to filter fields starting with 'user')"
type="text"
class="form-control">
@ -88,7 +88,7 @@
<em>The selected field filters don't match any known fields.</em>
</p>
<p ng-if="fieldFilters.sampleMatches">
Based on the choosen field filters, these are the known fields that would be excluded from document sources.
Based on the chosen field filters, these are the known fields that would be excluded from document sources.
</p>
<ul>
<li ng-repeat="match in fieldFilters.sampleMatches">{{match}}</li>

View file

@ -2,7 +2,7 @@ import { size, without } from 'lodash';
import uiModules from 'ui/modules';
import Notifier from 'ui/notify/notifier';
import { fieldWildcardMatcher } from 'ui/field_wildcard';
import FieldWildcardProvider from 'ui/field_wildcard';
import template from './field_filters.html';
import './field_filters.less';
@ -10,7 +10,8 @@ import './field_filters.less';
const notify = new Notifier();
uiModules.get('kibana')
.directive('settingsIndicesFieldFilters', function () {
.directive('settingsIndicesFieldFilters', function (Private) {
const { fieldWildcardMatcher } = Private(FieldWildcardProvider);
return {
restrict: 'E',
scope: {
@ -32,7 +33,7 @@ uiModules.get('kibana')
$scope.$watch('indexPattern.fieldFilters', (filters) => {
const values = filters.map(f => f.value);
const filter = fieldWildcardMatcher(values);
const matches = $scope.indexPattern.fields.map(f => f.name).filter(filter).sort();
const matches = $scope.indexPattern.getNonScriptedFields().map(f => f.name).filter(filter).sort();
this.sampleMatches = size(matches) ? matches : null;
});
}

View file

@ -17,7 +17,6 @@ module.exports = function initDefaultFieldProps(fields) {
analyzed: true,
doc_values: false,
scripted: false,
exclude: false,
count: 0
});
@ -28,7 +27,6 @@ module.exports = function initDefaultFieldProps(fields) {
analyzed: false,
doc_values: true,
scripted: false,
exclude: false,
count: 0
});
}
@ -38,7 +36,6 @@ module.exports = function initDefaultFieldProps(fields) {
analyzed: false,
doc_values: true,
scripted: false,
exclude: false,
count: 0
});
}

View file

@ -7,12 +7,13 @@ import RequestQueueProvider from '../_request_queue';
import ErrorHandlersProvider from '../_error_handlers';
import FetchProvider from '../fetch';
import DecorateQueryProvider from './_decorate_query';
import { fieldWildcardFilter } from '../../field_wildcard';
import FieldWildcardProvider from '../../field_wildcard';
export default function SourceAbstractFactory(Private, Promise, PromiseEmitter) {
let requestQueue = Private(RequestQueueProvider);
let errorHandlers = Private(ErrorHandlersProvider);
let courierFetch = Private(FetchProvider);
let { fieldWildcardFilter } = Private(FieldWildcardProvider);
function SourceAbstract(initialState, strategy) {
let self = this;

View file

@ -83,38 +83,6 @@
</div>
</div>
<div class="form-group">
<span class="pull-right text-info hintbox-label" ng-click="editor.showExcludeHelp = !editor.showExcludeHelp">
<i class="fa fa-info"></i> Help
</span>
<label><input ng-disabled="isMetaField" type="checkbox" ng-model="editor.field.exclude"> Exclude from _source</label>
<div class="hintbox" ng-if="isMetaField">
<h4 class="hintbox-heading">
<i class="fa fa-warning text-warning"></i> Field Exclusion
</h4>
<p>
You cannot exclude metadata fields.
</p>
</div>
<div class="hintbox" ng-if="editor.showExcludeHelp">
<h4 class="hintbox-heading">
<i class="fa fa-info text-info"></i> Field Exclusion
</h4>
<p>
If checked, this field will be filtered from the <b>_source</b> of each document using
<a target="_window" href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering.html">source filtering<i aria-hidden="true" class="fa-link fa"></i></a>. This only impacts views that fetch the _source for documents, like Discover or the doc table.
</p>
<p>
If this field is explicitly selected in your saved search, then it will not be excluded.
</p>
</div>
</div>
<div ng-if="editor.field.scripted">
<div class="form-group">
<label>Script</label>

View file

@ -36,7 +36,6 @@ uiModules
self.indexPattern = $scope.getIndexPattern();
self.field = shadowCopy($scope.getField());
self.formatParams = self.field.format.params();
$scope.isMetaField = _.contains(metaFields, self.field.name);
// only init on first create
self.creating = !self.indexPattern.fields.byName[self.field.name];

View file

@ -1,8 +1,20 @@
import expect from 'expect.js';
import ngMock from 'ng_mock';
import { makeRegEx, fieldWildcardFilter } from '../field_wildcard';
import FieldWildcardProvider from '../../field_wildcard';
describe('fieldWildcard', function () {
let fieldWildcardFilter;
let makeRegEx;
beforeEach(ngMock.module('kibana'));
beforeEach(ngMock.inject(function (config, Private) {
config.set('metaFields', ['_id', '_type', '_source']);
const fieldWildcard = Private(FieldWildcardProvider);
fieldWildcardFilter = fieldWildcard.fieldWildcardFilter;
makeRegEx = fieldWildcard.makeRegEx;
}));
describe('makeRegEx', function () {
it('matches * in any position', function () {
expect('aaaaaabbbbbbbcccccc').to.match(makeRegEx('*a*b*c*'));
@ -38,6 +50,18 @@ describe('fieldWildcard', function () {
expect(original.filter(filter)).to.eql(original);
});
it('does not filter metaFields', function () {
const filter = fieldWildcardFilter([ '_*' ]);
const original = [
'_id',
'_type',
'_typefake'
];
expect(original.filter(filter)).to.eql(['_id', '_type']);
});
it('filters values that match the globs', function () {
const filter = fieldWildcardFilter([
'f*',

View file

@ -1,18 +1,24 @@
import { escapeRegExp, memoize } from 'lodash';
export const makeRegEx = memoize(function makeRegEx(glob) {
return new RegExp('^' + glob.split('*').map(escapeRegExp).join('.*') + '$');
});
export default function fieldWildcard(config) {
const metaFields = config.get('metaFields');
export function fieldWildcardMatcher(globs) {
return function matcher(val) {
return globs.some(p => makeRegEx(p).test(val));
};
}
const makeRegEx = memoize(function makeRegEx(glob) {
return new RegExp('^' + glob.split('*').map(escapeRegExp).join('.*') + '$');
});
export function fieldWildcardFilter(globs) {
const matcher = fieldWildcardMatcher(globs);
return function filter(val) {
return !matcher(val);
};
}
function fieldWildcardMatcher(globs) {
return function matcher(val) {
return metaFields.indexOf(val) === -1 && globs.some(p => makeRegEx(p).test(val));
};
}
function fieldWildcardFilter(globs) {
const matcher = fieldWildcardMatcher(globs, config);
return function filter(val) {
return !matcher(val);
};
}
return { makeRegEx, fieldWildcardMatcher, fieldWildcardFilter };
};

View file

@ -2,7 +2,7 @@ import ObjDefine from 'ui/utils/obj_define';
import IndexPatternsFieldFormatFieldFormatProvider from 'ui/index_patterns/_field_format/field_format';
import IndexPatternsFieldTypesProvider from 'ui/index_patterns/_field_types';
import RegistryFieldFormatsProvider from 'ui/registry/field_formats';
export default function FieldObjectProvider(Private, shortDotsFilter, $rootScope, Notifier, config) {
export default function FieldObjectProvider(Private, shortDotsFilter, $rootScope, Notifier) {
let notify = new Notifier({ location: 'IndexPattern Field' });
let FieldFormat = Private(IndexPatternsFieldFormatFieldFormatProvider);
let fieldTypes = Private(IndexPatternsFieldTypesProvider);
@ -42,12 +42,10 @@ export default function FieldObjectProvider(Private, shortDotsFilter, $rootScope
let scripted = !!spec.scripted;
let sortable = spec.name === '_score' || ((indexed || scripted) && type.sortable);
let filterable = spec.name === '_id' || scripted || (indexed && type.filterable);
let isMetaField = config.get('metaFields').includes(spec.name);
obj.fact('name');
obj.fact('type');
obj.writ('count', spec.count || 0);
obj.fact('exclude', Boolean(!isMetaField && spec.exclude));
// scripted objs
obj.fact('scripted', scripted);

View file

@ -138,14 +138,9 @@ export default function IndexPatternFactory(Private, timefilter, Notifier, confi
};
// Get the source filtering configuration for that index.
// Fields which name appears in the given columns array will not be excluded.
self.getSourceFiltering = function (columns) {
self.getSourceFiltering = function () {
return {
exclude: self
.getNonScriptedFields()
.filter(field => field.exclude && !_.contains(columns, field.name))
.map(field => field.name)
.concat(self.fieldFilters.map(filter => filter.value))
exclude: self.fieldFilters.map(filter => filter.value)
};
};
@ -309,18 +304,8 @@ export default function IndexPatternFactory(Private, timefilter, Notifier, confi
};
self._fetchFields = function () {
const existingFieldsByName = _.get(self, 'fields.byName', {});
return mapper.getFieldsForIndexPattern(self, true)
.then(function (fields) {
// copy over kibana-added properties from existing fields
fields.forEach(function (field) {
var existingField = existingFieldsByName[field.name];
if (existingField) {
field.exclude = existingField.exclude;
}
});
// append existing scripted fields
fields = fields.concat(self.getScriptedFields());