KQL
You're reading the main branch's readme. Please visit hexdocs for the latest published documentation.
Parser for a simplified version of the Kibana query language into an AST.
What is supported?
- Comparison operators:
>,>=,<,<=,: - Quoted and unquoted values, including escape characters:
make:"foo bar",make:foo\ bar - Not, and, & or operators:
NOT make:foo,make:foo AND model:bar,make:foo OR model:bar - Grouping expressions with
():make:foo OR (make:bar AND model:bar) - UTF-8 values:
make:čšć - Glob values:
make:foo* - Value lists:
make: (foo OR bar),make: [foo, bar] - Nested fields, dotted or braced:
first.second: fooandfirst: { second: foo and third: bar }both produce anestednode per path segment, wrapping the expression at the leaf - Quoted field names:
"first.second": foois a literal field name â quoting makes the dots characters rather than path separators
What is missing?
- Matching multiple fields (glob values in field name):
make*:foo
Installation
def deps do
[
{:kql, "~> 0.2.0"}
]
end
Examples
iex> KQL.parse("make:foo")
{:ok, %{
"ast" => %{
"field" => "make",
"operator" => "=",
"type" => "comparison",
"value" => %{
"type" => "value",
"term" => "foo",
"glob" => false,
"quoted" => false
}
},
"meta" => %{
"original_query" => "make:foo",
"version" => "0.2.0"
}
}}
Globs are supported too:
iex> KQL.parse("make:A* AND model:*X")
{:ok, %{
"ast" => %{
"type" => "and",
"terms" => [%{
"type" => "comparison",
"field" => "make",
"operator" => "=",
"value" => %{
"type" => "value",
"term" => "A*",
"glob" => true,
"quoted" => false
}
},
%{
"type" => "comparison",
"field" => "model",
"operator" => "=",
"value" => %{
"type" => "value",
"term" => "*X",
"glob" => true,
"quoted" => false
}
}]
},
"meta" => %{
"original_query" => "make:A* AND model:*X",
"version" => "0.2.0"
}
}}
A dotted field name is a path, producing one nested node per dot with the
comparison at the leaf:
iex> KQL.parse("car.make:alfa")
{:ok, %{
"ast" => %{
"type" => "nested",
"path" => "car",
"term" => %{
"type" => "comparison",
"field" => "make",
"operator" => "=",
"value" => %{
"type" => "value",
"term" => "alfa",
"glob" => false,
"quoted" => false
}
}
},
"meta" => %{
"original_query" => "car.make:alfa",
"version" => "0.2.0"
}
}}
The braced form wraps a whole expression instead of a single comparison, so
car:{make:alfa} and car.make:alfa produce the same AST:
iex> KQL.parse("car:{make:alfa AND year>=2020}")
{:ok, %{
"ast" => %{
"type" => "nested",
"path" => "car",
"term" => %{
"type" => "and",
"terms" => [%{
"type" => "comparison",
"field" => "make",
"operator" => "=",
"value" => %{
"type" => "value",
"term" => "alfa",
"glob" => false,
"quoted" => false
}
},
%{
"type" => "comparison",
"field" => "year",
"operator" => ">=",
"value" => %{
"type" => "value",
"term" => "2020",
"glob" => false,
"quoted" => false
}
}]
}
},
"meta" => %{
"original_query" => "car:{make:alfa AND year>=2020}",
"version" => "0.2.0"
}
}}
Quoting a field name makes it literal, so its dots are characters rather than
path separators and the result stays a plain comparison:
iex> KQL.parse(~S|"car.make":alfa|)
{:ok, %{
"ast" => %{
"type" => "comparison",
"field" => "car.make",
"operator" => "=",
"value" => %{
"type" => "value",
"term" => "alfa",
"glob" => false,
"quoted" => false
}
},
"meta" => %{
"original_query" => "\"car.make\":alfa",
"version" => "0.2.0"
}
}}