Thank you, Matthias, for the detailed implementation and explanation. As of now, our capability is limited to executing interactive queries on individual partitions. To illustrate:
Consider the IQv2StoreIntegrationTest: We have two partitions: Partition0 contains key-value pairs: <0,0> and <2,2>. Partition1 contains key-value pairs: <1,1> and <3,3>. When executing RangeQuery.withRange(1,3), the results are: Partition0: [2] Partition1: [1, 3] To support functionalities like reverseRange and reverseAll, we can introduce the withDescendingKeys() method. For instance, using RangeQuery.withRange(1,3).withDescendingKeys(), the anticipated results are: Partition0: [2] Partition1: [3, 1] In response to Hao's inquiry about the boundary issue, please refer to the StoreQueryUtils class. The code snippet: iterator = kvStore.range(lowerRange.orElse(null), upperRange.orElse(null)); indicates that when implementing range in each store, it's structured like: @Override public KeyValueIterator<Bytes, byte[]> range(final Bytes from, final Bytes to) { if (from != null && to != null && from.compareTo(to) > 0) { This section performs the necessary checks. Sincerely, Hanyu On Thu, Oct 5, 2023 at 9:52 AM Hanyu (Peter) Zheng <pzh...@confluent.io> wrote: > Hi, Hao, > > In this case, it will return an empty set or list in the end. > > Sincerely, > Hanyu > > On Wed, Oct 4, 2023 at 10:29 PM Matthias J. Sax <mj...@apache.org> wrote: > >> Great discussion! >> >> It seems the only open question might be about ordering guarantees? >> IIRC, we had a discussion about this in the past. >> >> >> Technically (at least from my POV), existing `RangeQuery` does not have >> a guarantee that data is return in any specific order (not even on a per >> partitions bases). It just happens that RocksDB (and as pointed out by >> Hanyu already, also the built-in in-memory store that is base on a >> tree-map) allows us to return data ordered by key; as mentioned already, >> this guarantee is limited on a per partition basis. >> >> If there would be custom store base on a hashed key-value store, this >> store could implement RangeQuery and return data (even for a single >> partition) with no ordering, without violating the contract. >> >> >> >> Thus, it could actually make sense, to extend `RangeQuery` and allow >> three options: no-order, ascending, descending. For our existing >> Rocks/InMemory implementations, no-order could be equal to ascending and >> nothing changes effectively, but it might be a better API contract? -- >> If we assume that there might be a custom hash-based store, such a store >> could reject a query if "ascending" is required, or might need to do >> more work to implement it (up to the store maintainer). This is actually >> the beauty of IQv2 that different stores can pick what queries they want >> to support. >> >> From an API contract point of view, it seems confusing to say: >> specifying nothing means no guarantee (or ascending if the store can >> offer it), but descending can we explicitly request. Thus, a hash-based >> store, might be able to accept "order not specified query", but would >> reject "descending". This seems to be somewhat unbalanced? >> >> Thus, I am wondering if we should actually add `withAscendingKeys()`, >> too, even if it won't impact our current RocksDB/In-Memory >> implementations? >> >> >> The second question is about per-partition or across-partition ordering: >> it's not possible right now to actually offer across-partition ordering >> the way IQv2 is setup. The reason is, that the store that implements a >> query type, is always a single shard. Thus, the implementation does not >> have access to other shards. It's hard-coded inside Kafka Streams, to >> query each shared, and to "accumulate" partial results, and return the >> back to the user. Note that the API is: >> >> >> > StateQueryResult<R> result = KafkaStreams.query(...); >> > Map<Integer, QueryResult<R>> resultPerPartitions = >> result.getPartitionResults(); >> >> >> Thus, if we would want to offer across-partition ordering, we cannot do >> it right now, because Kafka Streams does not know anything about the >> semantics of the query it distributes... -- the result is an unknown >> type <R>. We would need to extend IQv2 with an additional mechanism, >> that allows users to plug in more custom code to "merge" multiple >> partitions result into a "global result". This is clearly out-of-scope >> for this KIP and would require a new KIP by itself. >> >> I seems that this contract, which is independent of the query type is >> not well understood, and thus a big +1 to fix the documentation. I don't >> think that this KIP must "define" anything, but it might of course be >> worth to add the explanation why the KIP cannot even offer >> global-ordering, as it's defined/limited by the IQv2 "framework" itself, >> not the individual queries. >> >> >> >> -Matthias >> >> >> >> >> On 10/4/23 4:38 PM, Hao Li wrote: >> > Hi Hanyu, >> > >> > Thanks for the KIP! Seems there are already a lot of good discussions. I >> > only have two comments: >> > >> > 1. Please make it clear in >> > ``` >> > /** >> > * Interactive range query using a lower and upper bound to filter >> the >> > keys returned. >> > * @param lower The key that specifies the lower bound of the range >> > * @param upper The key that specifies the upper bound of the range >> > * @param <K> The key type >> > * @param <V> The value type >> > */ >> > public static <K, V> RangeQuery<K, V> withRange(final K lower, >> final K >> > upper) { >> > return new RangeQuery<>(Optional.ofNullable(lower), >> > Optional.ofNullable(upper), true); >> > } >> > ``` >> > that a `null` in lower or upper parameter means it's unbounded. >> > 2. What's the behavior if lower is 3 and upper is 1? Is it >> IllegalArgument >> > or will this return an empty result? Maybe also clarify this in the >> > document. >> > >> > Thanks, >> > Hao >> > >> > >> > On Wed, Oct 4, 2023 at 9:27 AM Hanyu (Peter) Zheng >> > <pzh...@confluent.io.invalid> wrote: >> > >> >> For testing purposes, we previously used a Set to record the results in >> >> IQv2StoreIntegrationTest. Let's take an example where we now have two >> >> partitions and four key-value pairs: <0,0> in p0, <1,1> in p1, <2,2> >> in p0, >> >> and <3,3> in p1. >> >> >> >> If we execute withRange(1,3), it will return a Set of <1, 2, 3>. >> However, >> >> if we run withRange(1,3).withDescendingKeys(), and still use a Set, the >> >> result will again be a Set of <1,2,3>. This means we won't be able to >> >> determine whether the results have been reversed. >> >> >> >> To resolve this ambiguity, I've switched to using a List to record the >> >> results, ensuring the order of retrieval from partitions p0 and p1. So, >> >> withRange(1,3) would yield a List of [2, 1, 3], whereas >> >> withRange(1,3).withDescendingKeys() would produce a List of [2,3,1]. >> >> >> >> This ordering makes sense since RocksDB sorts its keys, and >> InMemoryStore >> >> uses a TreeMap structure, which means the keys are already sorted. >> >> >> >> Sincerely, >> >> Hanyu >> >> >> >> On Wed, Oct 4, 2023 at 9:25 AM Hanyu (Peter) Zheng < >> pzh...@confluent.io> >> >> wrote: >> >> >> >>> Hi, Bruno >> >>> >> >>> Thank you for your suggestions, I will update them soon. >> >>> Sincerely, >> >>> >> >>> Hanyu >> >>> >> >>> On Wed, Oct 4, 2023 at 9:25 AM Hanyu (Peter) Zheng < >> pzh...@confluent.io> >> >>> wrote: >> >>> >> >>>> Hi, Lucas, >> >>>> >> >>>> Thank you for your suggestions. >> >>>> I will update the KIP and code together. >> >>>> >> >>>> Sincerely, >> >>>> Hanyu >> >>>> >> >>>> On Tue, Oct 3, 2023 at 8:16 PM Hanyu (Peter) Zheng < >> pzh...@confluent.io >> >>> >> >>>> wrote: >> >>>> >> >>>>> If we use WithDescendingKeys() to generate a RangeQuery to do the >> >>>>> reveseQuery, how do we achieve the methods like withRange, >> >> withUpperBound, >> >>>>> and withLowerBound only in this method? >> >>>>> >> >>>>> On Tue, Oct 3, 2023 at 8:01 PM Hanyu (Peter) Zheng < >> >> pzh...@confluent.io> >> >>>>> wrote: >> >>>>> >> >>>>>> I believe there's no need to introduce a method like >> >>>>>> WithDescendingKeys(). Instead, we can simply add a reverse flag to >> >>>>>> RangeQuery. Each method within RangeQuery would then accept an >> >> additional >> >>>>>> parameter. If the reverse is set to true, it would indicate the >> >> results >> >>>>>> should be reversed. >> >>>>>> >> >>>>>> Initially, I introduced a reverse variable. When set to false, the >> >>>>>> RangeQuery class behaves normally. However, when reverse is set to >> >> true, >> >>>>>> the RangeQuery essentially takes on the functionality of >> >> ReverseRangeQuery. >> >>>>>> Further details can be found in the "Rejected Alternatives" >> section. >> >>>>>> >> >>>>>> In my perspective, RangeQuery is a class responsible for creating a >> >>>>>> series of RangeQuery objects. It offers methods such as withRange, >> >>>>>> withUpperBound, and withLowerBound, allowing us to generate objects >> >>>>>> representing different queries. I'm unsure how adding a >> >>>>>> withDescendingOrder() method would be compatible with the other >> >> methods, >> >>>>>> especially considering that, based on KIP 969, WithDescendingKeys() >> >> doesn't >> >>>>>> appear to take any input variables. And if withDescendingOrder() >> >> doesn't >> >>>>>> accept any input, how does it return a RangeQuery? >> >>>>>> >> >>>>>> On Tue, Oct 3, 2023 at 4:37 PM Hanyu (Peter) Zheng < >> >> pzh...@confluent.io> >> >>>>>> wrote: >> >>>>>> >> >>>>>>> Hi, Colt, >> >>>>>>> The underlying structure of inMemoryKeyValueStore is treeMap. >> >>>>>>> Sincerely, >> >>>>>>> Hanyu >> >>>>>>> >> >>>>>>> On Tue, Oct 3, 2023 at 4:34 PM Hanyu (Peter) Zheng < >> >>>>>>> pzh...@confluent.io> wrote: >> >>>>>>> >> >>>>>>>> Hi Bill, >> >>>>>>>> 1. I will update the KIP in accordance with the PR and >> synchronize >> >>>>>>>> their future updates. >> >>>>>>>> 2. I will use that name. >> >>>>>>>> 3. you mean add something about ordering at the motivation >> section? >> >>>>>>>> >> >>>>>>>> Sincerely, >> >>>>>>>> Hanyu >> >>>>>>>> >> >>>>>>>> >> >>>>>>>> On Tue, Oct 3, 2023 at 4:29 PM Hanyu (Peter) Zheng < >> >>>>>>>> pzh...@confluent.io> wrote: >> >>>>>>>> >> >>>>>>>>> Hi, Walker, >> >>>>>>>>> >> >>>>>>>>> 1. I will update the KIP in accordance with the PR and >> synchronize >> >>>>>>>>> their future updates. >> >>>>>>>>> 2. I will use that name. >> >>>>>>>>> 3. I'll provide additional details in that section. >> >>>>>>>>> 4. I intend to utilize rangeQuery to achieve what we're >> referring >> >> to >> >>>>>>>>> as reverseQuery. In essence, reverseQuery is merely a term. To >> >> clear up any >> >>>>>>>>> ambiguity, I'll make necessary adjustments to the KIP. >> >>>>>>>>> >> >>>>>>>>> Sincerely, >> >>>>>>>>> Hanyu >> >>>>>>>>> >> >>>>>>>>> >> >>>>>>>>> >> >>>>>>>>> On Tue, Oct 3, 2023 at 4:09 PM Hanyu (Peter) Zheng < >> >>>>>>>>> pzh...@confluent.io> wrote: >> >>>>>>>>> >> >>>>>>>>>> Ok, I will change it back to following the code, and update >> them >> >>>>>>>>>> together. >> >>>>>>>>>> >> >>>>>>>>>> On Tue, Oct 3, 2023 at 2:27 PM Walker Carlson >> >>>>>>>>>> <wcarl...@confluent.io.invalid> wrote: >> >>>>>>>>>> >> >>>>>>>>>>> Hello Hanyu, >> >>>>>>>>>>> >> >>>>>>>>>>> Looking over your kip things mostly make sense but I have a >> >> couple >> >>>>>>>>>>> of >> >>>>>>>>>>> comments. >> >>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>>>> 1. You have "withDescandingOrder()". I think you mean >> >>>>>>>>>>> "descending" :) >> >>>>>>>>>>> Also there are still a few places in the do where its >> called >> >>>>>>>>>>> "setReverse" >> >>>>>>>>>>> 2. Also I like "WithDescendingKeys()" better >> >>>>>>>>>>> 3. I'm not sure of what ordering guarantees we are >> offering. >> >>>>>>>>>>> Perhaps we >> >>>>>>>>>>> can add a section to the motivation clearly spelling out >> the >> >>>>>>>>>>> current >> >>>>>>>>>>> ordering and the new offering? >> >>>>>>>>>>> 4. When you say "use unbounded reverseQuery to achieve >> >>>>>>>>>>> reverseAll" do >> >>>>>>>>>>> you mean "use unbounded RangeQuery to achieve >> reverseAll"? as >> >>>>>>>>>>> far as I can >> >>>>>>>>>>> tell we don't have a reverseQuery as a named object? >> >>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>>>> Looking good so far >> >>>>>>>>>>> >> >>>>>>>>>>> best, >> >>>>>>>>>>> Walker >> >>>>>>>>>>> >> >>>>>>>>>>> On Tue, Oct 3, 2023 at 2:13 PM Colt McNealy < >> c...@littlehorse.io >> >>> >> >>>>>>>>>>> wrote: >> >>>>>>>>>>> >> >>>>>>>>>>>> Hello Hanyu, >> >>>>>>>>>>>> >> >>>>>>>>>>>> Thank you for the KIP. I agree with Matthias' proposal to >> keep >> >>>>>>>>>>> the naming >> >>>>>>>>>>>> convention consistent with KIP-969. I favor the >> >>>>>>>>>>> `.withDescendingKeys()` >> >>>>>>>>>>>> name. >> >>>>>>>>>>>> >> >>>>>>>>>>>> I am curious about one thing. RocksDB guarantees that records >> >>>>>>>>>>> returned >> >>>>>>>>>>>> during a range scan are lexicographically ordered by the >> bytes >> >>>>>>>>>>> of the keys >> >>>>>>>>>>>> (either ascending or descending order, as specified in the >> >>>>>>>>>>> query). This >> >>>>>>>>>>>> means that results within a single partition are indeed >> >>>>>>>>>>> ordered.** My >> >>>>>>>>>>>> reading of KIP-805 suggests to me that you don't need to >> >> specify >> >>>>>>>>>>> the >> >>>>>>>>>>>> partition number you are querying in IQv2, which means that >> you >> >>>>>>>>>>> can have a >> >>>>>>>>>>>> valid reversed RangeQuery over a store with "multiple >> >>>>>>>>>>> partitions" in it. >> >>>>>>>>>>>> >> >>>>>>>>>>>> Currently, IQv1 does not guarantee order of keys in this >> >>>>>>>>>>> scenario. Does >> >>>>>>>>>>>> IQv2 support ordering across partitions? Such an >> implementation >> >>>>>>>>>>> would >> >>>>>>>>>>>> require opening a rocksdb range scan** on multiple rocksdb >> >>>>>>>>>>> instances (one >> >>>>>>>>>>>> per partition), and polling the first key of each. Whether or >> >>>>>>>>>>> not this is >> >>>>>>>>>>>> ordered, could we please add that to the documentation? >> >>>>>>>>>>>> >> >>>>>>>>>>>> **(How is this implemented/guaranteed in an >> >>>>>>>>>>> `inMemoryKeyValueStore`? I >> >>>>>>>>>>>> don't know about that implementation). >> >>>>>>>>>>>> >> >>>>>>>>>>>> Colt McNealy >> >>>>>>>>>>>> >> >>>>>>>>>>>> *Founder, LittleHorse.dev* >> >>>>>>>>>>>> >> >>>>>>>>>>>> >> >>>>>>>>>>>> On Tue, Oct 3, 2023 at 1:35 PM Hanyu (Peter) Zheng >> >>>>>>>>>>>> <pzh...@confluent.io.invalid> wrote: >> >>>>>>>>>>>> >> >>>>>>>>>>>>> ok, I will update it. Thank you Matthias >> >>>>>>>>>>>>> >> >>>>>>>>>>>>> Sincerely, >> >>>>>>>>>>>>> Hanyu >> >>>>>>>>>>>>> >> >>>>>>>>>>>>> On Tue, Oct 3, 2023 at 11:23 AM Matthias J. Sax < >> >>>>>>>>>>> mj...@apache.org> >> >>>>>>>>>>>> wrote: >> >>>>>>>>>>>>> >> >>>>>>>>>>>>>> Thanks for the KIP Hanyu! >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> I took a quick look and it think the proposal makes sense >> >>>>>>>>>>> overall. >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> A few comments about how to structure the KIP. >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> As you propose to not add `ReverseRangQuery` class, the >> >> code >> >>>>>>>>>>> example >> >>>>>>>>>>>>>> should go into "Rejected Alternatives" section, not in the >> >>>>>>>>>>> "Proposed >> >>>>>>>>>>>>>> Changes" section. >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> For the `RangeQuery` code example, please omit all existing >> >>>>>>>>>>> methods >> >>>>>>>>>>>> etc, >> >>>>>>>>>>>>>> and only include what will be added/changed. This make it >> >>>>>>>>>>> simpler to >> >>>>>>>>>>>>>> read the KIP. >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> nit: typo >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>>> the fault value is false >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> Should be "the default value is false". >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> Not sure if `setReverse()` is the best name. Maybe >> >>>>>>>>>>>> `withDescandingOrder` >> >>>>>>>>>>>>>> (or similar, I guess `withReverseOrder` would also work) >> >>>>>>>>>>> might be >> >>>>>>>>>>>>>> better? Would be good to align to KIP-969 proposal that >> >>>>>>>>>>> suggest do use >> >>>>>>>>>>>>>> `withDescendingKeys` methods for "reverse key-range"; if we >> >>>>>>>>>>> go with >> >>>>>>>>>>>>>> `withReverseOrder` we should change KIP-969 accordingly. >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> Curious to hear what others think about naming this >> >>>>>>>>>>> consistently across >> >>>>>>>>>>>>>> both KIPs. >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> -Matthias >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>>> On 10/3/23 9:17 AM, Hanyu (Peter) Zheng wrote: >> >>>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>> >> >>>>>>>>>>>> >> >>>>>>>>>>> >> >> >> https://cwiki.apache.org/confluence/display/KAFKA/KIP-985%3A+Add+reverseRange+and+reverseAll+query+over+kv-store+in+IQv2 >> >>>>>>>>>>>>>>> >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>> >> >>>>>>>>>>>>> >> >>>>>>>>>>>>> -- >> >>>>>>>>>>>>> >> >>>>>>>>>>>>> [image: Confluent] <https://www.confluent.io> >> >>>>>>>>>>>>> Hanyu (Peter) Zheng he/him/his >> >>>>>>>>>>>>> Software Engineer Intern >> >>>>>>>>>>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>>>>>>>>>> Follow us: [image: Blog] >> >>>>>>>>>>>>> < >> >>>>>>>>>>>>> >> >>>>>>>>>>>> >> >>>>>>>>>>> >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>>>>>>>>>>>>> [image: >> >>>>>>>>>>>>> Twitter] <https://twitter.com/ConfluentInc>[image: >> LinkedIn] >> >>>>>>>>>>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: >> >> Slack] >> >>>>>>>>>>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>>>>>>>>>> <https://youtube.com/confluent> >> >>>>>>>>>>>>> >> >>>>>>>>>>>>> [image: Try Confluent Cloud for Free] >> >>>>>>>>>>>>> < >> >>>>>>>>>>>>> >> >>>>>>>>>>>> >> >>>>>>>>>>> >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>>>>>>>>>>>>> >> >>>>>>>>>>>>> >> >>>>>>>>>>>> >> >>>>>>>>>>> >> >>>>>>>>>> >> >>>>>>>>>> >> >>>>>>>>>> -- >> >>>>>>>>>> >> >>>>>>>>>> [image: Confluent] <https://www.confluent.io> >> >>>>>>>>>> Hanyu (Peter) Zheng he/him/his >> >>>>>>>>>> Software Engineer Intern >> >>>>>>>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>>>>>>> Follow us: [image: Blog] >> >>>>>>>>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>>>>>>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>>>>>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>>>>>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>>>>>>> <https://youtube.com/confluent> >> >>>>>>>>>> >> >>>>>>>>>> [image: Try Confluent Cloud for Free] >> >>>>>>>>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>>>>>>>> >> >>>>>>>>> >> >>>>>>>>> >> >>>>>>>>> -- >> >>>>>>>>> >> >>>>>>>>> [image: Confluent] <https://www.confluent.io> >> >>>>>>>>> Hanyu (Peter) Zheng he/him/his >> >>>>>>>>> Software Engineer Intern >> >>>>>>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>>>>>> Follow us: [image: Blog] >> >>>>>>>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>>>>>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>>>>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>>>>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>>>>>> <https://youtube.com/confluent> >> >>>>>>>>> >> >>>>>>>>> [image: Try Confluent Cloud for Free] >> >>>>>>>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>>>>>>> >> >>>>>>>> >> >>>>>>>> >> >>>>>>>> -- >> >>>>>>>> >> >>>>>>>> [image: Confluent] <https://www.confluent.io> >> >>>>>>>> Hanyu (Peter) Zheng he/him/his >> >>>>>>>> Software Engineer Intern >> >>>>>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>>>>> Follow us: [image: Blog] >> >>>>>>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>>>>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>>>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>>>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>>>>> <https://youtube.com/confluent> >> >>>>>>>> >> >>>>>>>> [image: Try Confluent Cloud for Free] >> >>>>>>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>>>>>> >> >>>>>>> >> >>>>>>> >> >>>>>>> -- >> >>>>>>> >> >>>>>>> [image: Confluent] <https://www.confluent.io> >> >>>>>>> Hanyu (Peter) Zheng he/him/his >> >>>>>>> Software Engineer Intern >> >>>>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>>>> Follow us: [image: Blog] >> >>>>>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>>>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>>>> <https://youtube.com/confluent> >> >>>>>>> >> >>>>>>> [image: Try Confluent Cloud for Free] >> >>>>>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>>>>> >> >>>>>> >> >>>>>> >> >>>>>> -- >> >>>>>> >> >>>>>> [image: Confluent] <https://www.confluent.io> >> >>>>>> Hanyu (Peter) Zheng he/him/his >> >>>>>> Software Engineer Intern >> >>>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>>> Follow us: [image: Blog] >> >>>>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>>> <https://youtube.com/confluent> >> >>>>>> >> >>>>>> [image: Try Confluent Cloud for Free] >> >>>>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>>>> >> >>>>> >> >>>>> >> >>>>> -- >> >>>>> >> >>>>> [image: Confluent] <https://www.confluent.io> >> >>>>> Hanyu (Peter) Zheng he/him/his >> >>>>> Software Engineer Intern >> >>>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>>> Follow us: [image: Blog] >> >>>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>>> <https://youtube.com/confluent> >> >>>>> >> >>>>> [image: Try Confluent Cloud for Free] >> >>>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>>> >> >>>> >> >>>> >> >>>> -- >> >>>> >> >>>> [image: Confluent] <https://www.confluent.io> >> >>>> Hanyu (Peter) Zheng he/him/his >> >>>> Software Engineer Intern >> >>>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>>> Follow us: [image: Blog] >> >>>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>>> <https://youtube.com/confluent> >> >>>> >> >>>> [image: Try Confluent Cloud for Free] >> >>>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>>> >> >>> >> >>> >> >>> -- >> >>> >> >>> [image: Confluent] <https://www.confluent.io> >> >>> Hanyu (Peter) Zheng he/him/his >> >>> Software Engineer Intern >> >>> +1 (213) 431-7193 <+1+(213)+431-7193> >> >>> Follow us: [image: Blog] >> >>> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >>> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >>> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >>> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >>> <https://youtube.com/confluent> >> >>> >> >>> [image: Try Confluent Cloud for Free] >> >>> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >>> >> >> >> >> >> >> -- >> >> >> >> [image: Confluent] <https://www.confluent.io> >> >> Hanyu (Peter) Zheng he/him/his >> >> Software Engineer Intern >> >> +1 (213) 431-7193 <+1+(213)+431-7193> >> >> Follow us: [image: Blog] >> >> < >> >> >> https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog >> >>> [image: >> >> Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] >> >> <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] >> >> <https://slackpass.io/confluentcommunity>[image: YouTube] >> >> <https://youtube.com/confluent> >> >> >> >> [image: Try Confluent Cloud for Free] >> >> < >> >> >> https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic >> >>> >> >> >> > >> > > > -- > > [image: Confluent] <https://www.confluent.io> > Hanyu (Peter) Zheng he/him/his > Software Engineer Intern > +1 (213) 431-7193 <+1+(213)+431-7193> > Follow us: [image: Blog] > <https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog>[image: > Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] > <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] > <https://slackpass.io/confluentcommunity>[image: YouTube] > <https://youtube.com/confluent> > > [image: Try Confluent Cloud for Free] > <https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic> > -- [image: Confluent] <https://www.confluent.io> Hanyu (Peter) Zheng he/him/his Software Engineer Intern +1 (213) 431-7193 <+1+(213)+431-7193> Follow us: [image: Blog] <https://www.confluent.io/blog?utm_source=footer&utm_medium=email&utm_campaign=ch.email-signature_type.community_content.blog>[image: Twitter] <https://twitter.com/ConfluentInc>[image: LinkedIn] <https://www.linkedin.com/in/hanyu-peter-zheng/>[image: Slack] <https://slackpass.io/confluentcommunity>[image: YouTube] <https://youtube.com/confluent> [image: Try Confluent Cloud for Free] <https://www.confluent.io/get-started?utm_campaign=tm.fm-apac_cd.inbound&utm_source=gmail&utm_medium=organic>