Skip to content

EQL: implement math functions: add, divide, module, multiply, subtract#55137

Merged
aleksmaus merged 7 commits intoelastic:masterfrom
aleksmaus:feature/eql_math
Apr 24, 2020
Merged

EQL: implement math functions: add, divide, module, multiply, subtract#55137
aleksmaus merged 7 commits intoelastic:masterfrom
aleksmaus:feature/eql_math

Conversation

@aleksmaus
Copy link
Copy Markdown
Contributor

@aleksmaus aleksmaus commented Apr 14, 2020

Related to #54846

@aleksmaus aleksmaus requested review from costin and rw-access April 14, 2020 00:20
@aleksmaus
Copy link
Copy Markdown
Contributor Author

aleksmaus commented Apr 14, 2020

and of course QL tests fail with

20:23:05 org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.BinaryArithmeticProcessorTests > testTree FAILED
20:23:05     java.lang.AssertionError: expected:<1> but was:<1.0>
20:23:05         at __randomizedtesting.SeedInfo.seed([1FE6DDAE374DA7C1:8FF2CE9796CC0ED1]:0)

and

20:23:06 org.elasticsearch.xpack.ql.optimizer.OptimizerRulesTests > testArithmeticFolding FAILED
20:23:06     java.lang.AssertionError: expected:<2> but was:<2.3333333333333335>

Will reach out tomorrow.

@cbuescher cbuescher added the :Analytics/EQL EQL querying label Apr 15, 2020
@elasticmachine
Copy link
Copy Markdown
Collaborator

Pinging @elastic/es-ql (:Query Languages/EQL)

@costin costin requested review from astefan and matriv April 16, 2020 11:18
@aleksmaus aleksmaus requested a review from imotov April 17, 2020 01:28
@aleksmaus aleksmaus marked this pull request as ready for review April 17, 2020 01:28
Copy link
Copy Markdown
Contributor

@matriv matriv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Copy Markdown
Contributor

@imotov imotov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The division by 0 exception currently look like this:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "script_exception",
        "reason" : "runtime error",
        "script_stack" : [
          "org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics.div(Arithmetics.java:100)",
          "org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics$NumericArithmetic.wrap(Arithmetics.java:30)",
          "org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.doApply(DefaultBinaryArithmeticOperation.java:45)",
          "org.elasticsearch.xpack.ql.expression.predicate.PredicateBiFunction.apply(PredicateBiFunction.java:24)",
          "org.elasticsearch.xpack.ql.expression.function.scalar.whitelist.InternalQlScriptUtils.div(InternalQlScriptUtils.java:128)",
          "InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.eq(InternalQlScriptUtils.div(params.v0,InternalQlScriptUtils.docValue(doc,params.v1)),params.v2))",
          "                                                                                                                       ^---- HERE"
        ],
        "script" : "InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.eq(InternalQlScriptUtils.div(params.v0,InternalQlScriptUtils.docValue(doc,params.v1)),params.v2))",
        "lang" : "painless",
        "position" : {
          "offset" : 119,
          "start" : 0,
          "end" : 156
        }
      }
    ],
    "type" : "search_phase_execution_exception",
    "reason" : "all shards failed",
    "phase" : "query",
    "grouped" : true,
    "failed_shards" : [
      {
        "shard" : 0,
        "index" : "endgame",
        "node" : "hOOT6db-REOOt2zKF-eYRQ",
        "reason" : {
          "type" : "script_exception",
          "reason" : "runtime error",
          "script_stack" : [
            "org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics.div(Arithmetics.java:100)",
            "org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.Arithmetics$NumericArithmetic.wrap(Arithmetics.java:30)",
            "org.elasticsearch.xpack.ql.expression.predicate.operator.arithmetic.DefaultBinaryArithmeticOperation.doApply(DefaultBinaryArithmeticOperation.java:45)",
            "org.elasticsearch.xpack.ql.expression.predicate.PredicateBiFunction.apply(PredicateBiFunction.java:24)",
            "org.elasticsearch.xpack.ql.expression.function.scalar.whitelist.InternalQlScriptUtils.div(InternalQlScriptUtils.java:128)",
            "InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.eq(InternalQlScriptUtils.div(params.v0,InternalQlScriptUtils.docValue(doc,params.v1)),params.v2))",
            "                                                                                                                       ^---- HERE"
          ],
          "script" : "InternalQlScriptUtils.nullSafeFilter(InternalQlScriptUtils.eq(InternalQlScriptUtils.div(params.v0,InternalQlScriptUtils.docValue(doc,params.v1)),params.v2))",
          "lang" : "painless",
          "position" : {
            "offset" : 119,
            "start" : 0,
            "end" : 156
          },
          "caused_by" : {
            "type" : "arithmetic_exception",
            "reason" : "/ by zero"
          }
        }
      }
    ]
  },
  "status" : 400
}

I wonder if it might make sense to suppress it the same way we do in SQL, where it looks like this:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "arithmetic_exception",
        "reason" : "/ by zero"
      }
    ],
    "type" : "arithmetic_exception",
    "reason" : "/ by zero"
  },
  "status" : 500
}

Copy link
Copy Markdown
Contributor

@astefan astefan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left few comments.


[[queries]]
expected_event_ids = [82]
query = "file where serial_event_id % 40 == 2"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have more complex math operations?
Few ideas:

  • put the constant first and the field name second
  • use the minus sign for the field as well: file where -serial_event_id + 100 == 18
  • have a more complex arithmetic set of operations: file where serial_event_id + ((1 + 3) * 2 / (3 - 1)) * 2 == 90 OR 70 + serial_event_id < 100

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added all of the above.

@aleksmaus
Copy link
Copy Markdown
Contributor Author

@imotov I like the idea for simpler response for this kind of cases. I compared with the SQL execution code, it doesn't look like it uses "painless" though, so the exception from div raised pretty much to the response. Need to dig to understand better. Can look into this after merging this PR.

Copy link
Copy Markdown
Contributor

@astefan astefan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general LGTM. But I left few minor comments.

expected_event_ids = [82, 83]
query = "file where serial_event_id / 2 == 41"

# Additional EQL queries with arithmetic operations that were not part of the original EQL implementation
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be worth adding these new tests to the original EQL implementation, as well.


[[queries]]
expected_event_ids = [82]
query = "file where serial_event_id + ((1 + 3) * 2 / (3 - 1)) * 2 == 90 or 70 + serial_event_id < 100"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct.
70 + serial_event_id < 100 should match all event IDs from 1 to 29. Why is expected_event_ids only 82? Or I am missing something?

Copy link
Copy Markdown
Contributor Author

@aleksmaus aleksmaus Apr 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right.
Looks like something changed, even the simple query like
doesn't return all 102 records:

  1> [2020-04-23T19:17:13,335][INFO ][o.e.x.e.EqlActionIT      ] [test] [65.test -> file where true] before test
  1> [2020-04-23T19:17:13,346][INFO ][o.e.x.e.EqlActionIT      ] [test] [55, 59, 60, 61, 65, 66, 67, 70, 71, 72, 75, 76, 77, 81, 82, 83, 86, 87, 88, 91, 92, 95, 96]

looking

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nevermind .... the other events have different type

Copy link
Copy Markdown
Contributor Author

@aleksmaus aleksmaus Apr 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to query against process type that leads to more results

},
// Arithmetic
new FunctionDefinition[] {
def(Add.class, Add::new,"add"),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace before the last parameter.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


[[queries]]
expected_event_ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
query = "process where serial_event_id + ((1 + 3) * 2 / (3 - 1)) * 2 == 90 or 70 + serial_event_id < 100"
Copy link
Copy Markdown
Contributor

@rw-access rw-access Apr 23, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it tests the query folding more than the integration, and folds to

process where serial_event_id + 8 == 90 or serial_event_id < 100.

Since serial_event_id of 82 is a file event, we don't have any results that match the left side.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, thanks, updated the test to match the left side of or condition.

Copy link
Copy Markdown
Contributor

@rw-access rw-access left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

left a comment about the test_queries_supported.toml, but other than that lgtm

@aleksmaus aleksmaus merged commit 9e79e5d into elastic:master Apr 24, 2020
aleksmaus added a commit to aleksmaus/elasticsearch that referenced this pull request Apr 24, 2020
elastic#55137)

* EQL: implement math functions: add, divide, module, multiply, subtract
aleksmaus added a commit that referenced this pull request Apr 24, 2020
#55137) (#55737)

* EQL: implement math functions: add, divide, module, multiply, subtract
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Analytics/EQL EQL querying

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants