From 7087358ae2fb212811d480ec8641a46167946c82 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Wed, 5 Feb 2020 13:33:07 +0200 Subject: [PATCH] EQL: Add field resolution and verification (#51872) Add basic field resolution inside the Analyzer and a basic Verifier to check for any unresolved fields. --- x-pack/plugin/eql/build.gradle | 1 + .../xpack/eql/analysis/AnalysisUtils.java | 97 +++++++++++++++++++ .../xpack/eql/analysis/Analyzer.java | 64 +++++++++++- .../xpack/eql/analysis/AnalyzerRule.java | 27 ++++++ .../xpack/eql/analysis/Verifier.java | 2 + .../function/EqlFunctionRegistry.java | 15 +++ .../xpack/eql/parser/LogicalPlanBuilder.java | 10 +- .../xpack/eql/session/Configuration.java | 3 +- .../xpack/eql/session/EqlSession.java | 4 +- .../elasticsearch/xpack/eql/EqlTestUtils.java | 34 +++++++ .../xpack/eql/analysis/VerifierTests.java | 65 +++++++++++++ .../xpack/eql/parser/LogicalPlanTests.java | 11 +-- .../src/test/resources/mapping-default.json | 55 +++++++++++ .../ql/plan/logical/UnresolvedRelation.java | 6 +- .../xpack/ql/type/TypesTests.java | 13 ++- 15 files changed, 381 insertions(+), 26 deletions(-) create mode 100644 x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalysisUtils.java create mode 100644 x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalyzerRule.java create mode 100644 x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/EqlFunctionRegistry.java create mode 100644 x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/EqlTestUtils.java create mode 100644 x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java create mode 100644 x-pack/plugin/eql/src/test/resources/mapping-default.json diff --git a/x-pack/plugin/eql/build.gradle b/x-pack/plugin/eql/build.gradle index 47b66cf7151a6..65ec91f6ca83a 100644 --- a/x-pack/plugin/eql/build.gradle +++ b/x-pack/plugin/eql/build.gradle @@ -27,6 +27,7 @@ dependencies { testCompile project(':test:framework') testCompile project(path: xpackModule('core'), configuration: 'testArtifacts') testCompile project(path: xpackModule('security'), configuration: 'testArtifacts') + testCompile project(path: xpackModule('ql'), configuration: 'testArtifacts') testCompile project(path: ':modules:reindex', configuration: 'runtime') testCompile project(path: ':modules:parent-join', configuration: 'runtime') testCompile project(path: ':modules:analysis-common', configuration: 'runtime') diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalysisUtils.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalysisUtils.java new file mode 100644 index 0000000000000..51764b139c2c5 --- /dev/null +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalysisUtils.java @@ -0,0 +1,97 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.eql.analysis; + +import org.elasticsearch.xpack.ql.expression.Attribute; +import org.elasticsearch.xpack.ql.expression.FieldAttribute; +import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; +import org.elasticsearch.xpack.ql.type.DataTypes; +import org.elasticsearch.xpack.ql.type.InvalidMappedField; +import org.elasticsearch.xpack.ql.type.UnsupportedEsField; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static java.util.stream.Collectors.toList; + +public final class AnalysisUtils { + + private AnalysisUtils() {} + + // + // Shared methods around the analyzer rules + // + static Attribute resolveAgainstList(UnresolvedAttribute u, Collection attrList) { + return resolveAgainstList(u, attrList, false); + } + + static Attribute resolveAgainstList(UnresolvedAttribute u, Collection attrList, boolean allowCompound) { + List matches = new ArrayList<>(); + + // first take into account the qualified version + boolean qualified = u.qualifier() != null; + + for (Attribute attribute : attrList) { + if (!attribute.synthetic()) { + boolean match = qualified ? Objects.equals(u.qualifiedName(), attribute.qualifiedName()) : + // if the field is unqualified + // first check the names directly + (Objects.equals(u.name(), attribute.name()) + // but also if the qualifier might not be quoted and if there's any ambiguity with nested fields + || Objects.equals(u.name(), attribute.qualifiedName())); + if (match) { + matches.add(attribute.withLocation(u.source())); + } + } + } + + // none found + if (matches.isEmpty()) { + return null; + } + + if (matches.size() == 1) { + return handleSpecialFields(u, matches.get(0), allowCompound); + } + + return u.withUnresolvedMessage( + "Reference [" + u.qualifiedName() + "] is ambiguous (to disambiguate use quotes or qualifiers); matches any of " + + matches.stream().map(a -> "\"" + a.qualifier() + "\".\"" + a.name() + "\"").sorted().collect(toList())); + } + + private static Attribute handleSpecialFields(UnresolvedAttribute u, Attribute named, boolean allowCompound) { + // if it's a object/compound type, keep it unresolved with a nice error message + if (named instanceof FieldAttribute) { + FieldAttribute fa = (FieldAttribute) named; + + // incompatible mappings + if (fa.field() instanceof InvalidMappedField) { + named = u.withUnresolvedMessage("Cannot use field [" + fa.name() + "] due to ambiguities being " + + ((InvalidMappedField) fa.field()).errorMessage()); + } + // unsupported types + else if (DataTypes.isUnsupported(fa.dataType())) { + UnsupportedEsField unsupportedField = (UnsupportedEsField) fa.field(); + if (unsupportedField.hasInherited()) { + named = u.withUnresolvedMessage("Cannot use field [" + fa.name() + "] with unsupported type [" + + unsupportedField.getOriginalType() + "] " + "in hierarchy (field [" + unsupportedField.getInherited() + "])"); + } else { + named = u.withUnresolvedMessage( + "Cannot use field [" + fa.name() + "] with unsupported type [" + unsupportedField.getOriginalType() + "]"); + } + } + // compound fields + else if (allowCompound == false && DataTypes.isPrimitive(fa.dataType()) == false) { + named = u.withUnresolvedMessage( + "Cannot use field [" + fa.name() + "] type [" + fa.dataType().typeName() + "] only its subfields"); + } + } + return named; + } +} \ No newline at end of file diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Analyzer.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Analyzer.java index eb741da145e30..9f18db3c9202b 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Analyzer.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Analyzer.java @@ -6,13 +6,20 @@ package org.elasticsearch.xpack.eql.analysis; +import org.elasticsearch.xpack.ql.expression.Attribute; +import org.elasticsearch.xpack.ql.expression.NamedExpression; +import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.rule.Rule; import org.elasticsearch.xpack.ql.rule.RuleExecutor; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import static java.util.Arrays.asList; +import static org.elasticsearch.xpack.eql.analysis.AnalysisUtils.resolveAgainstList; public class Analyzer extends RuleExecutor { @@ -26,7 +33,8 @@ public Analyzer(FunctionRegistry functionRegistry, Verifier verifier) { @Override protected Iterable.Batch> batches() { - Batch resolution = new Batch("Resolution"); + Batch resolution = new Batch("Resolution", + new ResolveRefs()); return asList(resolution); } @@ -42,4 +50,56 @@ private LogicalPlan verify(LogicalPlan plan) { } return plan; } -} + + private static class ResolveRefs extends AnalyzeRule { + + @Override + protected LogicalPlan rule(LogicalPlan plan) { + // if the children are not resolved, there's no way the node can be resolved + if (!plan.childrenResolved()) { + return plan; + } + + // okay, there's a chance so let's get started + if (log.isTraceEnabled()) { + log.trace("Attempting to resolve {}", plan.nodeString()); + } + + return plan.transformExpressionsUp(e -> { + if (e instanceof UnresolvedAttribute) { + UnresolvedAttribute u = (UnresolvedAttribute) e; + List childrenOutput = new ArrayList<>(); + for (LogicalPlan child : plan.children()) { + childrenOutput.addAll(child.output()); + } + NamedExpression named = resolveAgainstList(u, childrenOutput); + // if resolved, return it; otherwise keep it in place to be resolved later + if (named != null) { + if (log.isTraceEnabled()) { + log.trace("Resolved {} to {}", u, named); + } + return named; + } + } + return e; + }); + } + } + + abstract static class AnalyzeRule extends Rule { + + // transformUp (post-order) - that is first children and then the node + // but with a twist; only if the tree is not resolved or analyzed + @Override + public final LogicalPlan apply(LogicalPlan plan) { + return plan.transformUp(t -> t.analyzed() || skipResolved() && t.resolved() ? t : rule(t), typeToken()); + } + + @Override + protected abstract LogicalPlan rule(SubPlan plan); + + protected boolean skipResolved() { + return true; + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalyzerRule.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalyzerRule.java new file mode 100644 index 0000000000000..27352e39a2a05 --- /dev/null +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/AnalyzerRule.java @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.eql.analysis; + +import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.rule.Rule; + +public abstract class AnalyzerRule extends Rule { + + // transformUp (post-order) - that is first children and then the node + // but with a twist; only if the tree is not resolved or analyzed + @Override + public final LogicalPlan apply(LogicalPlan plan) { + return plan.transformUp(t -> t.analyzed() || skipResolved() && t.resolved() ? t : rule(t), typeToken()); + } + + @Override + protected abstract LogicalPlan rule(SubPlan plan); + + protected boolean skipResolved() { + return true; + } +} diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java index 51dfb6a3d971c..071bdb0cb0029 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/analysis/Verifier.java @@ -99,6 +99,8 @@ Collection verify(LogicalPlan plan) { }); }); } + + failures.addAll(localFailures); }); return failures; diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/EqlFunctionRegistry.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/EqlFunctionRegistry.java new file mode 100644 index 0000000000000..a219d4482d0a0 --- /dev/null +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/expression/function/EqlFunctionRegistry.java @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.eql.expression.function; + +import org.elasticsearch.xpack.ql.expression.function.FunctionRegistry; + +public class EqlFunctionRegistry extends FunctionRegistry { + + public EqlFunctionRegistry() { + } +} diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java index d87bf06c62855..3662a1d7c351b 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/parser/LogicalPlanBuilder.java @@ -11,20 +11,16 @@ import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute; import org.elasticsearch.xpack.ql.expression.predicate.logical.And; import org.elasticsearch.xpack.ql.expression.predicate.operator.comparison.Equals; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.plan.logical.UnresolvedRelation; import org.elasticsearch.xpack.ql.tree.Source; import org.elasticsearch.xpack.ql.type.DataTypes; -import static java.util.Collections.emptyMap; - public abstract class LogicalPlanBuilder extends ExpressionBuilder { // TODO: these need to be made configurable - private static final String EVENT_TYPE = "event.category"; - private static final EsIndex esIndex = new EsIndex("", emptyMap()); + private static final String EVENT_TYPE = "event_type"; @Override public LogicalPlan visitEventQuery(EqlBaseParser.EventQueryContext ctx) { @@ -43,6 +39,6 @@ public LogicalPlan visitEventQuery(EqlBaseParser.EventQueryContext ctx) { } - return new Filter(source(ctx), new EsRelation(Source.EMPTY, esIndex, false), condition); + return new Filter(source(ctx), new UnresolvedRelation(Source.EMPTY, null, "", false, ""), condition); } } diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/Configuration.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/Configuration.java index c0bfbf389e0f7..d1aff0749e448 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/Configuration.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/Configuration.java @@ -23,8 +23,7 @@ public class Configuration extends org.elasticsearch.xpack.ql.session.Configurat private QueryBuilder filter; public Configuration(String[] indices, ZoneId zi, String username, String clusterName, QueryBuilder filter, - TimeValue requestTimeout, - boolean includeFrozen, String clientId) { + TimeValue requestTimeout, boolean includeFrozen, String clientId) { super(zi, username, clusterName); diff --git a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/EqlSession.java b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/EqlSession.java index 20cbd3cf98fe8..babc35fff181f 100644 --- a/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/EqlSession.java +++ b/x-pack/plugin/eql/src/main/java/org/elasticsearch/xpack/eql/session/EqlSession.java @@ -13,6 +13,7 @@ import org.elasticsearch.xpack.eql.analysis.PreAnalyzer; import org.elasticsearch.xpack.eql.execution.PlanExecutor; import org.elasticsearch.xpack.eql.optimizer.Optimizer; +import org.elasticsearch.xpack.eql.parser.EqlParser; import org.elasticsearch.xpack.eql.plan.physical.PhysicalPlan; import org.elasticsearch.xpack.eql.planner.Planner; import org.elasticsearch.xpack.ql.index.IndexResolver; @@ -97,7 +98,6 @@ private void preAnalyze(LogicalPlan parsed, ActionListener list private LogicalPlan doParse(String eql, List params) { Check.isTrue(params.isEmpty(), "Parameters were given despite being ignored - server bug"); - //LogicalPlan plan = new EqlParser().createStatement(eql); - throw new UnsupportedOperationException(); + return new EqlParser().createStatement(eql); } } \ No newline at end of file diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/EqlTestUtils.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/EqlTestUtils.java new file mode 100644 index 0000000000000..dba73070690db --- /dev/null +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/EqlTestUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +package org.elasticsearch.xpack.eql; + +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.xpack.eql.session.Configuration; + +import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength; +import static org.elasticsearch.test.ESTestCase.randomBoolean; +import static org.elasticsearch.test.ESTestCase.randomNonNegativeLong; +import static org.elasticsearch.test.ESTestCase.randomZone; + +public final class EqlTestUtils { + + private EqlTestUtils() {} + + public static final Configuration TEST_CFG = new Configuration(new String[] { "none" }, org.elasticsearch.xpack.ql.util.DateUtils.UTC, + "nobody", "cluster", null, TimeValue.timeValueSeconds(30), false, ""); + + public static Configuration randomConfiguration() { + return new Configuration(new String[] {randomAlphaOfLength(16)}, + randomZone(), + randomAlphaOfLength(16), + randomAlphaOfLength(16), + null, + new TimeValue(randomNonNegativeLong()), + randomBoolean(), + randomAlphaOfLength(16)); + } +} diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java new file mode 100644 index 0000000000000..64f5328b5d1f6 --- /dev/null +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/analysis/VerifierTests.java @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.eql.analysis; + +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.eql.expression.function.EqlFunctionRegistry; +import org.elasticsearch.xpack.eql.parser.EqlParser; +import org.elasticsearch.xpack.ql.index.EsIndex; +import org.elasticsearch.xpack.ql.index.IndexResolution; +import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.type.EsField; +import org.elasticsearch.xpack.ql.type.TypesTests; + +import java.util.Map; + +public class VerifierTests extends ESTestCase { + + private EqlParser parser = new EqlParser(); + private IndexResolution index = IndexResolution.valid(new EsIndex("test", loadEqlMapping("mapping-default.json"))); + + private LogicalPlan accept(IndexResolution resolution, String eql) { + PreAnalyzer preAnalyzer = new PreAnalyzer(); + Analyzer analyzer = new Analyzer(new EqlFunctionRegistry(), new Verifier()); + return analyzer.analyze(preAnalyzer.preAnalyze(parser.createStatement(eql), resolution)); + } + + private LogicalPlan accept(String eql) { + return accept(index, eql); + } + + private String error(String sql) { + return error(index, sql); + } + + private String error(IndexResolution resolution, String eql) { + VerificationException e = expectThrows(VerificationException.class, () -> accept(resolution, eql)); + assertTrue(e.getMessage().startsWith("Found ")); + String header = "Found 1 problem(s)\nline "; + return e.getMessage().substring(header.length()); + } + + public void testBasicQuery() { + accept("foo where true"); + } + + public void testMissingColumn() { + assertEquals("1:11: Unknown column [xxx]", error("foo where xxx == 100")); + } + + public void testMisspelledColumn() { + assertEquals("1:11: Unknown column [md4], did you mean [md5]?", error("foo where md4 == 1")); + } + + public void testMisspelledColumnWithMultipleOptions() { + assertEquals("1:11: Unknown column [pib], did you mean any of [pid, ppid]?", error("foo where pib == 1")); + } + + + private static Map loadEqlMapping(String name) { + return TypesTests.loadMapping(name); + } +} diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/parser/LogicalPlanTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/parser/LogicalPlanTests.java index 157fd9fa4738c..3ee6955813648 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/parser/LogicalPlanTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/parser/LogicalPlanTests.java @@ -4,19 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ - package org.elasticsearch.xpack.eql.parser; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.ql.expression.Expression; -import org.elasticsearch.xpack.ql.index.EsIndex; -import org.elasticsearch.xpack.ql.plan.logical.EsRelation; import org.elasticsearch.xpack.ql.plan.logical.Filter; import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan; +import org.elasticsearch.xpack.ql.plan.logical.UnresolvedRelation; import org.elasticsearch.xpack.ql.tree.Source; -import static java.util.Collections.emptyMap; - public class LogicalPlanTests extends ESTestCase { private final EqlParser parser = new EqlParser(); @@ -27,9 +23,8 @@ public Expression expr(String source) { public void testEventQuery() { LogicalPlan fullQuery = parser.createStatement("process where process_name == 'net.exe'"); - Expression fullExpression = expr("event.category == 'process' and process_name == 'net.exe'"); - EsIndex esIndex = new EsIndex("", emptyMap()); + Expression fullExpression = expr("event_type == 'process' and process_name == 'net.exe'"); - assertEquals(fullQuery, new Filter(null, new EsRelation(Source.EMPTY, esIndex, false), fullExpression)); + assertEquals(fullQuery, new Filter(Source.EMPTY, new UnresolvedRelation(Source.EMPTY, null, "", false, ""), fullExpression)); } } diff --git a/x-pack/plugin/eql/src/test/resources/mapping-default.json b/x-pack/plugin/eql/src/test/resources/mapping-default.json new file mode 100644 index 0000000000000..2c87024f7f09a --- /dev/null +++ b/x-pack/plugin/eql/src/test/resources/mapping-default.json @@ -0,0 +1,55 @@ +{ + "properties" : { + "command_line" : { + "type" : "keyword" + }, + "event_type" : { + "type" : "keyword" + }, + "md5" : { + "type" : "keyword" + }, + "parent_process_name": { + "type" : "keyword" + }, + "parent_process_path": { + "type" : "keyword" + }, + "pid" : { + "type" : "long" + }, + "ppid" : { + "type" : "long" + }, + "process_name": { + "type" : "keyword" + }, + "process_path": { + "type" : "keyword" + }, + "subtype" : { + "type" : "keyword" + }, + "timestamp" : { + "type" : "date" + }, + "user" : { + "type" : "keyword" + }, + "user_name" : { + "type" : "keyword" + }, + "user_domain": { + "type" : "keyword" + }, + "hostname" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + } + } +} \ No newline at end of file diff --git a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/plan/logical/UnresolvedRelation.java b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/plan/logical/UnresolvedRelation.java index e0c569af21b1b..41d7555358177 100644 --- a/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/plan/logical/UnresolvedRelation.java +++ b/x-pack/plugin/ql/src/main/java/org/elasticsearch/xpack/ql/plan/logical/UnresolvedRelation.java @@ -89,11 +89,11 @@ public boolean equals(Object obj) { } UnresolvedRelation other = (UnresolvedRelation) obj; - return source().equals(other.source()) - && table.equals(other.table) + return Objects.equals(source(), other.source()) + && Objects.equals(table, other.table) && Objects.equals(alias, other.alias) && Objects.equals(frozen, other.frozen) - && unresolvedMsg.equals(other.unresolvedMsg); + && Objects.equals(unresolvedMsg, other.unresolvedMsg); } @Override diff --git a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java index 8057c1cd48348..9958d00b02929 100644 --- a/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java +++ b/x-pack/plugin/ql/src/test/java/org/elasticsearch/xpack/ql/type/TypesTests.java @@ -9,6 +9,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.test.ESTestCase; +import java.io.IOException; import java.io.InputStream; import java.util.Map; @@ -195,9 +196,17 @@ public static Map loadMapping(DataTypeRegistry registry, String } public static Map loadMapping(DataTypeRegistry registry, String name, Boolean ordered) { - boolean order = ordered != null ? ordered.booleanValue() : randomBoolean(); InputStream stream = TypesTests.class.getResourceAsStream("/" + name); assertNotNull("Could not find mapping resource:" + name, stream); - return Types.fromEs(registry, XContentHelper.convertToMap(JsonXContent.jsonXContent, stream, order)); + return loadMapping(registry, stream, ordered); + } + + public static Map loadMapping(DataTypeRegistry registry, InputStream stream, Boolean ordered) { + boolean order = ordered != null ? ordered.booleanValue() : randomBoolean(); + try (InputStream in = stream) { + return Types.fromEs(registry, XContentHelper.convertToMap(JsonXContent.jsonXContent, in, order)); + } catch (IOException ex) { + throw new RuntimeException(ex); + } } } \ No newline at end of file