Skip to content

ES|QL: add track for LOOKUP JOIN scale tests#719

Merged
luigidellaquila merged 17 commits intoelastic:masterfrom
luigidellaquila:esql_join_scale
Jan 9, 2025
Merged

ES|QL: add track for LOOKUP JOIN scale tests#719
luigidellaquila merged 17 commits intoelastic:masterfrom
luigidellaquila:esql_join_scale

Conversation

@luigidellaquila
Copy link
Contributor

@luigidellaquila luigidellaquila commented Dec 31, 2024

Adding a track to measure the performance of ES|QL LOOKUP JOIN at scale.

The PR contains

  • a set of scripts to generate the corpus
  • queries with the corresponding challenges
  • track configuration to load the corpus and run the queries

joins/README.md Outdated
Comment on lines 30 to 31
Copy link
Contributor

Choose a reason for hiding this comment

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

This assumes the file was generated with at least 1k documents.
This is likely true for small cardinality fields, but might not be the case for 100m.
I wonder if it is worth mentioning explicitly?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 I added a small note

{
"name": "esql_lookup_join_1k_keys_where_no_match",
"operation-type": "esql",
"query": "FROM join_base_idx | lookup join lookup_idx_1000_f10 on key_1000 | where concat(lookup_keyword_0, \"foo\") == \"bar\""
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now these queries work the same as the *keys_where_limit* (see above), but in the future we could be able to push down to lucene one of the two, but most likely not the other one.

@luigidellaquila luigidellaquila marked this pull request as ready for review January 7, 2025 09:23
@alex-spies alex-spies self-requested a review January 7, 2025 09:51
Copy link
Contributor

@gbanasiak gbanasiak left a comment

Choose a reason for hiding this comment

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

Many thanks for iterating. Forgot to mention earlier: if the track is serverless-ready please add joins in here. Can be done in a separate PR.

@luigidellaquila
Copy link
Contributor Author

Thanks @gbanasiak!
We are still fine-tuning the Serverless tests, I'll add it with a follow-up PR

@luigidellaquila luigidellaquila merged commit b3c872f into elastic:master Jan 9, 2025
13 checks passed
Copy link

@alex-spies alex-spies left a comment

Choose a reason for hiding this comment

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

Thanks a lot Luigi! Looks good, although I do have suggestions for further iterations on the track.

I think in a follow up, we should deliberately force the lookups onto the coordinator or the data nodes, resp. See my comment below.

Additionally, I'm curious about how the following queries would perform:

  • lookup join against a lookup index where the non-lookup fields contain large values (long strings or many multi-values, for instance) - but maybe that's less relevant as the default dataset has 10 additional text fields already.
  • What happens when the lookup indices have many rows matching the same keys? Maybe the default dataset should have some repetitions?

Especially the last one will be important IMHO as with the planned SQL-like semantics, the cardinality of the whole result set will be changing with every LOOKUP JOIN - but it's already interesting in the current state, as the current implementation may pool a lot of multivalues.

{
"name": "esql_lookup_join_1k_100k_200k_500k",
"operation-type": "esql",
"query": "FROM join_base_idx | lookup join lookup_idx_1000_f10 on key_1000 | rename lookup_keyword_0 as lk_1k | lookup join lookup_idx_100000_f10 on key_100000 | rename lookup_keyword_0 as lk_100k | lookup join lookup_idx_200000_f10 on key_200000 | rename lookup_keyword_0 as lk_200k | lookup join lookup_idx_500000_f10 on key_500000 | rename lookup_keyword_0 as lk_500k | keep id, key_1000, key_100000, key_200000, key_500000, lk_1k, lk_100k, lk_200k, lk_500k | limit 1000"

Choose a reason for hiding this comment

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

The limit 1000 at the end is pushed down, and therefore all lookups will happen on the coordinator node, I think. This means we also perform the lookups against max 1000 rows.

The same is true essentially for all other queries in this file because we add an implicit LIMIT 1000 per default.

I think it'd be good to have versions of these queries where we add a SORT ... at the end - this should force the lookups onto the data nodes (best to confirm, though, by looking at the plans).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I think it makes sense to have it as next iteration.
I'll add some queries right away

Choose a reason for hiding this comment

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

Actually, I realized I was being imprecise. The queries with a WHERE clause will not have the limit pushed down past the LOOKUP JOINs, because the WHERE clause should prevent the pushdown. So there's already queries that force the execution of LOOKUP JOINs onto the data nodes.

Comment on lines +82 to +88
./lookup_idx.sh 1000 10 1 | shuf | bzip2 -c > lookup_idx_1000_f10.json.bz2
./lookup_idx.sh 100000 10 1 | shuf | bzip2 -c > lookup_idx_100000_f10.json.bz2
./lookup_idx.sh 200000 10 1 | shuf | bzip2 -c > lookup_idx_200000_f10.json.bz2
./lookup_idx.sh 500000 10 1 | shuf | bzip2 -c > lookup_idx_500000_f10.json.bz2
./lookup_idx.sh 1000000 10 1 | shuf | bzip2 -c > lookup_idx_1000000_f10.json.bz2
./lookup_idx.sh 5000000 10 1 | shuf | bzip2 -c > lookup_idx_5000000_f10.json.bz2
./joins_main_idx.sh 10000000 | bzip2 -c > join_base_idx-10M.json.bz2

Choose a reason for hiding this comment

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

nit: maybe a lower number of lookup indices would be sufficient? Like, 1k, 50k, 1M, 10M?

I think it's more interesting to have different numbers of repetitions IMHO.

Comment on lines +137 to +143
{#
"operation": "esql_lookup_join_100k_keys_where_no_match",
"tags": ["lookup", "join"],
"clients": 1,
"warmup-iterations": 10,
"iterations": 50
#}

Choose a reason for hiding this comment

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

Are the ..._where_no_match challenges commented out, resp. is this on purpose?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it's on purpose. These are super expensive and just time out.
My plan is to run some iterations with a higher timeout (tens of minutes) and test the limits here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments