Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Lens] Add specific IP and Range/Interval sorting to datatable #87006

Merged
merged 11 commits into from
Jan 11, 2021

Conversation

dej611
Copy link
Contributor

@dej611 dej611 commented Dec 29, 2020

Summary

Fixes: #85431, enhances #84435

This PR adds a specific logic to sort IP and Range type of data into the custom datatable sorting.

The previous sorting function has been rewritten for performance reason: the lodash orderBy was using only a single field per time and to perform an IP sorting logic it should have accepted 8 functions (one per IPv6 part/block) or perform some hacky manipulation.

Some initial unit testing has been added for the sorting logic, with particular focus on IP and ranges.

How Range sorting works

The range sorting algorithm works as follow:

  • Make explicit each range data object (i.e. {gte: 1} => {gte: 1, lt: Infinity})
  • Perform a comparison on the gte
  • if gte is identical then compare the lt value
  • Flip the direction using a +1 / -1 multiplier

Screenshot 2020-12-29 at 18 16 41

Screenshot 2020-12-29 at 18 16 47

How IP sorting works

In order to achieve the IP sorting a new dependency was added ( ipaddr.js - note that was already a subdependency of webpack-web-server), to support IPv6 parsing in its multiple form.

The IP sorting algorithm works as follow:

  • parse the string and check if it's a valid IP address ( IPv4 or IPv6 format and ranges )
    • if not valid return a mock value that makes it sure to be the minimal value in the array (i.e. Other value) (opinion)
  • transform the parsed IP into a IPv6 address (any IPv4 can be mapped into a IPv6, but it is not true the other way around)
  • convert each IPv6 part/block into a 16bit integer and compare them. Stop at the first difference.
  • in case the two addresses are identical (diff = 0 for each part/block) then compare the string length: the shorter form should be considered "smaller" than the longer form ( opinion )
  • Flip the direction using a +1 / -1 multiplier

Screenshot 2020-12-29 at 18 33 58

Screenshot 2020-12-29 at 18 33 51

Checklist

@dej611 dej611 added Feature:Lens release_note:enhancement Team:Visualizations Visualization editors, elastic-charts and infrastructure v7.12.0 v8.0.0 labels Dec 30, 2020
@dej611
Copy link
Contributor Author

dej611 commented Dec 30, 2020

Explored the option to embed this code into the data plugin, but I saw some more piping required in order to use it into Lens datatable in this scenario. We could consider to move it later once the feature will be shared with other plugins (for instance, thinking of Visualize or Discover)

@dej611 dej611 marked this pull request as ready for review December 30, 2020 10:32
@dej611 dej611 requested a review from a team December 30, 2020 10:32
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-app (Team:KibanaApp)

Copy link
Contributor

@wylieconlon wylieconlon left a comment

Choose a reason for hiding this comment

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

Overall I think this code is simple and makes sense. Left a comment about the behavior of IP sorting which I think we should change, but LGTM.

it(`should provide the IP criteria for IP values (mixed values with invalid "Other" field) - ${direction}`, () => {
testSorting({
input: ['fc00::123', '192.168.1.50', '10.0.1.76', '8.8.8.8', '::1', 'Other'],
output: ['Other', '::1', '8.8.8.8', '10.0.1.76', '192.168.1.50', 'fc00::123'],
Copy link
Contributor

Choose a reason for hiding this comment

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

I noticed that Other was sorted to the beginning of the list- I kind of expected it to be sorted in a special way, always being at the end of the list regardless of the sort order. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Possible, sure.
It's really up to us to decide a value out of the range I guess: the current implementation, as I saw it, mimics the "blank" values on numeric fields, which are casted to 0.
Putting it at last should be straightforward as it knows already the direction.

if (!ipaddr.isValid(ip)) {
// for non valid IPs have the same behaviour as for now (we assume it's only the "Other" string)
// create a mock object which has all -Infinity values to be the last item
return { parts: Array(8).fill(-Infinity) };
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the result of this is that Other is always shown at the beginning of the list. Can we push it to the end instead, since I would want to show IPs in ascending order?

diff = ipA.parts[i] - ipB.parts[i];
}

// in case of same address but written in different styles, sort by string length
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice!

@dej611
Copy link
Contributor Author

dej611 commented Dec 30, 2020

Implemented the "always last" logic for strings in the IP sorter:

always_last_value

@tsullivan
Copy link
Member

Hi, I'm taking a look at the changes. In the meantime, the PR description needs a clearly written Release Note since this is an enhancement :)

@tsullivan
Copy link
Member

Hi, the IP field sorting changes look good!

When I tested sorting range field types, I wasn't able to see the field in Lens. In Management > Index Patterns, the field type is labelled as unknown:

image
image

To test the range field type, is a setup step needed?

@wylieconlon
Copy link
Contributor

wylieconlon commented Dec 31, 2020

Hi @tsullivan, Kibana doesn't support range types (although I have a separate PR for it here #76971). Marco was talking about the ranges aggregation, which you can set in Lens by going to Horizontal axis -> Intervals -> Custom intervals

@flash1293
Copy link
Contributor

@elasticmachine merge upstream

@flash1293
Copy link
Contributor

@elasticmachine merge upstream

Copy link
Contributor

@flash1293 flash1293 left a comment

Choose a reason for hiding this comment

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

Tested and works as expected, LGTM. Left one small nit about the code

}
// use a string sorter for the rest
return (rowA: Record<string, unknown>, rowB: Record<string, unknown>) => {
const aString = formatter?.convert(rowA[sortBy]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it possible there is no formatter? The types indicate otherwise, so if the will always be a formatter, we can remove the optional chaining - if it can actually be undefined, we should do something like this: aString = formatter ? formatter.convert(rowA[sortBy]) : rowA[sortBy], otherwise it will just compare undefined with undefined

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The formatFactory should ensure each column has a formatter:

firstTable.columns.forEach((column) => {
formatters[column.id] = formatFactory(column.meta?.params);
});

I'll remove the optional chaining here.

@dej611
Copy link
Contributor Author

dej611 commented Jan 11, 2021

@elasticmachine merge upstream

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

Module Count

Fewer modules leads to a faster build time

id before after diff
lens 463 465 +2

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
enterpriseSearch 1.8MB 1.8MB +20.0B
lens 1.0MB 1.0MB +17.1KB
total +17.1KB

Page load bundle

Size of the bundles that are downloaded on every page load. Target size is below 100kb

id before after diff
upgradeAssistant 60.1KB 60.1KB +20.0B

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@dej611 dej611 merged commit 132e851 into elastic:master Jan 11, 2021
@dej611 dej611 deleted the feature/lens/table-ip-sorting branch January 11, 2021 15:51
dej611 added a commit to dej611/kibana that referenced this pull request Jan 12, 2021
dej611 added a commit that referenced this pull request Jan 12, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature:Lens release_note:enhancement Team:Visualizations Visualization editors, elastic-charts and infrastructure v7.12.0 v8.0.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Lens] Provide a Parser and Comparable util for IP addresses
6 participants