+1 for me on Guozhang's proposal for changes to Joined. Thanks, Bill
On Thu, Jan 17, 2019 at 5:55 PM Matthias J. Sax <matth...@confluent.io> wrote: > Thanks for all the follow up comments! > > As I mentioned earlier, I am ok with adding overloads instead of using > Materialized to specify the processor name. Seems this is what the > majority of people prefers. > > I am also +1 on Guozhang's suggestion to deprecate `static > Joined#named()` and replace it with `static Joined#as` for consistency > and to deprecate getter `Joined#name()` for removal and introduce > `JoinedInternal` to access the name. > > @Guozhang: the vote is already up :) > > > -Matthias > > On 1/17/19 2:45 PM, Guozhang Wang wrote: > > Wow that's a lot of discussions in 6 days! :) Just catching up and > sharing > > my two cents here: > > > > 1. Materialized: I'm inclined to not let Materialized extending Named and > > add the overload as well. All the rationales have been very well > summarized > > before. Just to emphasize on John's points: Materialized is considered as > > the control object being leveraged by the optimization framework to > > determine if the state store should be physically materialized or not. So > > let's say if the user does not want to query the store (hence it can just > > be locally materialized), but still want to name the processor, they need > > to do either "count(Materialized.as(null).withName("processorName"));" or > > "count(Named.as("processorName"));" and neither of it is a bit hard to > > educate to users, and hence it looks that an overload function with two > > parameters are easier to understand. > > > > 2. As for `NamedOperation`: I've left a comment about it before, i.e. "1) > > Regarding the interface / function name, I'd propose we call the > interface > > `NamedOperation` which would be implemented by Produced / Consumed / > > Printed / Joined / Grouped / Suppressed (note I intentionally exclude > > Materialized here since its semantics is quite), and have the default > class > > that implements `NamedOperation` as `Named`, which would be used in our > > adding overload functions. The main reason is to have consistency in > > naming." And I think I'm on the same page with John with his more > detailed > > proposal. > > > > 3. As for `Joined`: I actually would suggest we bite the bullet and > remove > > it as well, because we are trying to fix some inconsistencies in this KIP > > anyways (or is that not agreed upon yet?), my thoughts were that we will > > have the following breaking renamings as below: > > > > 3.a) static Joined#named() -> Joined#as() > > 3.b) Joined#name() -> "deleted" > > > > > > I also think that we can start the voting thread asap since we are > > achieving to an consensus and the KIP deadline is approaching. The wiki > > page itself may still need to be updated though with the API breaking > > changes above. > > > > > > Guozhang > > > > > > On Thu, Jan 17, 2019 at 1:43 PM Florian Hussonnois < > fhussonn...@gmail.com> > > wrote: > > > >> Sorry, I've sent my previous mail to quickly. Unlike the Consumed, > Produced > >> and Grouped classes, the Joined class does have getter methods. So I > >> propose to keep the name() method only for this class. > >> For other classes the name will be accessible through XXXInternal > classes. > >> > >> Le jeu. 17 janv. 2019 à 22:39, John Roesler <j...@confluent.io> a > écrit : > >> > >>> Just to chime in regarding NamedInternal. That was my bad mental model > to > >>> blame. It is indeed coercion, not casting. Even more relevant, I'm not > a > >>> fan of the XInternal pattern, but it is the pattern we have. It would > be > >>> worse to start carving out exceptions. > >>> > >>> So I agree that we should have: > >>> * `NamedOperation` interface, declaring only the `withName(String)` > >> setter > >>> member > >>> * `Named implements NamedOperation` class with a protected `name` > field, > >>> set by the `withName` setter (and also other config objects would do > the > >>> same, e.g., `Grouped implements NamedOperation`) > >>> * `NamedInternal extends Named` class with a public (but internally > >>> targeted) `name()` getter to expose the name to the topology builder. > >>> Likewise all the other config classes that implement NamedOperation > would > >>> expose a `name()` getter for the same purpose. It's not in the public > >> API, > >>> but we should take care to make sure the getter method has the same > name > >>> everywhere for minimum confusion. > >>> > >>> Thanks, everyone! > >>> -John > >>> > >>> On Thu, Jan 17, 2019 at 12:09 PM Bill Bejeck <bbej...@gmail.com> > wrote: > >>> > >>>> I'm getting caught up with the current state of this KIP. > >>>> > >>>> I agree that the question on what to do with overloads is a difficult > >> one > >>>> to answer. > >>>> > >>>> Both John and Matthias have laid out their thoughts thoroughly, and > the > >>>> points made by both resonate with me. > >>>> > >>>> I've spent some time thinking about this, and while I have a problem > >> with > >>>> adding overloaded methods, I can't quite get comfortable with the > >> notion > >>> of > >>>> Materialized naming the processing node. For me, it comes down to the > >>> fact > >>>> that Materialized is used to configure the state store for an > >> individual > >>>> processing node and knows nothing of the operation itself. So I'll go > >>> with > >>>> adding the Named overload to methods taking a Materialized by a narrow > >>>> margin. > >>>> > >>>> As for the name method, I agree with Matthias that it's not consistent > >>> with > >>>> the approach we've taken so far whether for better or worse, but to > >> quote > >>>> Matthias, "that ship has sailed." IMHO adding the method for making > >>>> testing easier doesn't justify it, as there are ways to get the name > >> via > >>>> NamedInternal class. > >>>> > >>>> Just my 2 cents. > >>>> > >>>> Thanks, > >>>> Bill > >>>> > >>>> On Wed, Jan 16, 2019 at 5:40 PM Matthias J. Sax < > matth...@confluent.io > >>> > >>>> wrote: > >>>> > >>>>> Thanks for the details John. > >>>>> > >>>>> While I understand your argument that it is no optimal to use > >>>>> `Materialized` to set the processor name, I still slightly prefer > >> this > >>>>> option, because adding more overloads seems to be even worse to me. > >>>>> > >>>>> But I would also not block this KIP if the majority of people prefer > >> to > >>>>> add overloads instead of extending `Materialized`. > >>>>> > >>>>> > >>>>> However, I cannot follow your argument about `NamedOperation#name()` > >>>>> getter method. So far, all configuration classes don't have getters > >> and > >>>>> it seems to be inconsistent to add a single one now. We also don't > >> need > >>>>> any cast IMHO, as we would use the same construct as we do for all > >>> other > >>>>> config classed via `NamedInternal` to access the name: > >>>>> > >>>>>> final String name = new NamedInternal(named).name(); > >>>>> > >>>>> Maybe, it would have been better to add getters from the beginning on > >>>>> (even if I think it was the right decision to not add getters). > >>> However, > >>>>> this ship have sailed and if we want to add getters to avoid the > >>>>> `XxxInternal()` construct, we should do it for all classes -- > >> however, > >>>>> what would a user gain if we do this? It would just be a lot of > >> "noise" > >>>>> IMHO. > >>>>> > >>>>> > >>>>> @Florian: I would suggest to start a VOTE if you want to get this > >> into > >>>>> 2.2 release. The open questions seem to be minor and I think we can > >>>>> resolve them in parallel to the vote. > >>>>> > >>>>> > >>>>> > >>>>> -Matthias > >>>>> > >>>>> > >>>>> On 1/16/19 12:59 PM, John Roesler wrote: > >>>>>> Hi Matthias, > >>>>>> > >>>>>> One thing that we discussed earlier was to avoid creating ambiguity > >>> by > >>>>>> conflating config objects that configure an operation (like > >> Grouped) > >>>> with > >>>>>> config objects that configure an aspect of the operation (like > >>>>>> Materialized). > >>>>>> > >>>>>> It is natural for the Grouped config to extend Named, as doing so > >>>>> indicates > >>>>>> that grouping operations can be named (I.e., the name applies to > >> the > >>>>>> operation itself, which in turn makes it reasonable to use the > >>>>> operation's > >>>>>> name as a component in the related processors' and topics' names). > >>>>>> > >>>>>> But what would it mean for Materialized to extend Named? > >> Materialized > >>>>> only > >>>>>> configures the materialization of an operation's result, not the > >>>>> operation > >>>>>> itself, so I guess it would mean the name applies to the result of > >>> the > >>>>>> operation? It doesn't really work. > >>>>>> > >>>>>> Adding config objects to the DSL was an attempt to avoid overload > >>> bloat > >>>>> as > >>>>>> more aspects of operations need to be configured. > >>>>>> However, we made a mistake with Materialized, since (as noted) it > >>>> doesn't > >>>>>> configure the operation itself, but just one aspect of it. > >>>>>> We basically bagged a bunch of parameters into one, without solving > >>> the > >>>>>> problem structurally, and this is the result: > >>>>>> As soon as we need to configure a *different* aspect of the > >>> operation, > >>>> we > >>>>>> again need to add a new overload, and the cycle begins again. > >>>>>> > >>>>>> The proper solution here is to add an eponymous config object to > >> each > >>>>>> stateful operation, one which mixes in or composes the Materialized > >>>>> aspect > >>>>>> config and the Named aspect config. But this is a large API change, > >>> and > >>>>> we > >>>>>> decided on the middle ground of just adding Named as an optional > >>>>> parameter > >>>>>> via new overloads for now. > >>>>>> > >>>>>> A similar compromise was to go ahead and add a Named overload > >>> directly > >>>> to > >>>>>> all the operators that currently have no config object. > >>>>>> Again, the proper thing would be to add a new config class for each > >>>>>> individual operation, but it seemed like a drastic change. > >>>>>> We basically said that right now, we don't think we'll ever need to > >>>>>> configure another aspect of those operators than the name, and > >> we're > >>>>>> acknowledging that if we do, we'll have to created a small mess to > >>>> clean > >>>>> up. > >>>>>> It's really just a generalization of the same problem with > >>> Materialized > >>>>>> operations. > >>>>>> > >>>>>> To answer your question about the Named interface: > >>>>>> The primary reason is that Named is an aspect that is meant to be > >>> mixed > >>>>> in > >>>>>> with other config objects. > >>>>>> For example, Grouped can extend Named. > >>>>>> If we followed the pattern you've referenced, we would have a > >> public > >>>>>> interface Named with only the setter and a private class > >>> NamedInternal > >>>>> with > >>>>>> the setter and getter. > >>>>>> But would Grouped be a subclass of NamedInternal? > >>>>>> Then, we could only have one kind of aspect mixin, since Java > >> doesn't > >>>>> have > >>>>>> multiple class inheritance, or we'd have to decide if the next > >> thing > >>>>> should > >>>>>> be a superclass of Named or a subclass of Named and a superclass of > >>>>> Grouped. > >>>>>> Plus, in the implementation, instead of just casting Grouped to > >>>>>> GroupedInternal (which is already unclean design), we'd also be > >>> casting > >>>>>> Grouped to NamedInternal, which is super confusing. > >>>>>> > >>>>>> It's far cleaner all around just to use the type system "the right > >>>> way", > >>>>>> which is what we've proposed. > >>>>>> Any config class can mix in the Named aspect, and it inherits a > >>>> contract > >>>>> to > >>>>>> supply both the setter and the getter. > >>>>>> Our implementation can actually avoid any casting in this usage, > >>> since > >>>> we > >>>>>> can just call grouped.name() to get the name, instead of something > >>>> like > >>>>>> ((NamedInternal) grouped).name(). > >>>>>> > >>>>>> Plus, what harm does it do to let people get back the configuration > >>>>>> property that they *just set* on the config object? > >>>>>> It doesn't break encapsulation. > >>>>>> It would certainly make writing tests a lot easier for everyone. > >>>>>> > >>>>>> All around, I would advocate for moving toward this design for all > >>> the > >>>>>> config interfaces, as I've previously demonstrated how we've made > >> an > >>>>>> intractable mess out of the window config hierarchy by trying to be > >>>>> clever > >>>>>> and hiding the getters. > >>>>>> > >>>>>> I hope this helps, > >>>>>> -John > >>>>>> > >>>>>> > >>>>>> On Wed, Jan 16, 2019 at 12:59 AM Matthias J. Sax < > >>>> matth...@confluent.io> > >>>>>> wrote: > >>>>>> > >>>>>>> While I understand that it should be possible to specify store > >> name > >>>> and > >>>>>>> processor name independent from each other, it's still unclear to > >>> me, > >>>>>>> why we cannot use the `Materialized` parameter to specify the > >>>> processor > >>>>>>> name: > >>>>>>> > >>>>>>>> // only set the node name > >>>>>>>> #count(Named.as("processorName")); > >>>>>>>> > >>>>>>>> // only set the store name > >>>>>>>> #count(Materialized.as("storeName")); > >>>>>>>> > >>>>>>>> // set both > >>>>>>>> #count(Materialized.as("storeName").withName("processorName")); > >>>>>>> > >>>>>>> This this case, it might be good to rename `withName` to > >>>>>>> `withProcessorName` to avoid confusion with the store name. > >>>>>>> > >>>>>>> However, why do we need this: > >>>>>>> > >>>>>>>> #count(Materialized.as("storeName"), Named.as("processorName")); > >>>>>>> > >>>>>>> I would prefer to not add this overload. > >>>>>>> > >>>>>>> > >>>>>>> > >>>>>>> Strictly, we could also avoid `#count(Named)`, and set the > >> processor > >>>>>>> name only via: > >>>>>>> > >>>>>>>> #count(Materialized.as(null).withName("processorName")); > >>>>>>> > >>>>>>> I admit, it's a little clumsy, but would save us one more > >> overload. > >>>>>>> > >>>>>>> > >>>>>>> > >>>>>>> One more comment that I forgot last time: why do we add the getter > >>>>>>> `Named#name()`? All other configuration classes only define > >> setters > >>>> and > >>>>>>> we add getters only in the internal implementation. > >>>>>>> > >>>>>>> > >>>>>>> -Matthias > >>>>>>> > >>>>>>> On 1/13/19 4:22 AM, Florian Hussonnois wrote: > >>>>>>>> Hi Matthias, > >>>>>>>> > >>>>>>>> The reason for overloading the methods with Materialized > >> parameter > >>> is > >>>>>>>> regarding the semantic of this class. > >>>>>>>> The Materialized class allow to name a queryable store. if a name > >>> is > >>>>> set > >>>>>>>> then it will be used both to name the state-store and the > >>>>>>> changelog-topic. > >>>>>>>> If no name is given, then the provided Named will be used. > >>>>>>>> This allow to name the operation without having a queriable > >> store. > >>>>>>>> > >>>>>>>> So if my analysis is correct, we will end up with : > >>>>>>>> > >>>>>>>> Generated | Named | Joined / > >>>>>>> Grouped > >>>>>>>> | Materialized > >>>>>>>> > >>>>>>> > >>>>> > >>>> > >>> > >> > ------------------------------------------------------------------------------------------------- > >>>>>>>> Node | X | X | > >>> X > >>>>>>>> | > >>>>>>>> > >>>>>>> > >>>>> > >>>> > >>> > >> > ------------------------------------------------------------------------------------------------- > >>>>>>>> Repartition Topic | X | | X > >>>>>>>> | > >>>>>>>> > >>>>>>> > >>>>> > >>>> > >>> > >> > ------------------------------------------------------------------------------------------------- > >>>>>>>> Queryable Store | | | > >>>>>>>> | X > >>>>>>>> > >>>>>>> > >>>>> > >>>> > >>> > >> > ------------------------------------------------------------------------------------------------- > >>>>>>>> State store | X | X | > >> X > >>>>>>>> | X > >>>>>>>> > >>>>>>> > >>>>> > >>>> > >>> > >> > ------------------------------------------------------------------------------------------------- > >>>>>>>> Changelog Topic | X | X | X > >>>>>>>> | X > >>>>>>>> > >>>>>>> > >>>>> > >>>> > >>> > >> > ------------------------------------------------------------------------------------------------- > >>>>>>>> > >>>>>>>> Le dim. 13 janv. 2019 à 03:23, Matthias J. Sax < > >>>> matth...@confluent.io> > >>>>> a > >>>>>>>> écrit : > >>>>>>>> > >>>>>>>>> Just catching up on this KIP again. > >>>>>>>>> > >>>>>>>>> One nit. The KIP says: > >>>>>>>>> > >>>>>>>>>> In addition, the generated names have a few disadvantages to > >>>>> guarantee > >>>>>>>>> topology compatibilities. In fact, adding a new operator, using > >> a > >>>>>>>>> third-library doing some optimization to remove some operators > >> or > >>>>>>> upgrading > >>>>>>>>> to a new KafkaStreams version with internal API changes may > >>> changed > >>>>>>> suffix > >>>>>>>>> indexing for a large amount of the processor names. This will in > >>>> turn > >>>>>>>>> change the internal state store names, as well as internal topic > >>>> names > >>>>>>> as > >>>>>>>>> well. > >>>>>>>>>> > >>>>>>>>> > >>>>>>>>> This is not true any longer (I guess it was true, when the KIP > >> was > >>>>>>>>> initially proposed), because all stores/internal-topics can be > >>> named > >>>>>>>>> since 2.1 release. I would suggest to remove the paragraph. > >>>>>>>>> > >>>>>>>>> Overall, I like the Named/NamedOperation design. > >>>>>>>>> > >>>>>>>>> What is unclear to me thought is, why we need new overloads for > >>>>> methods > >>>>>>>>> that accept `Materialized`. To be more precise, I think it make > >>>> sense > >>>>> to > >>>>>>>>> add an overload that only takes `Named`, but not one that takes > >>> both > >>>>>>>>> `Named` and `Materialized`. For example: > >>>>>>>>> > >>>>>>>>> KGroupedStream#count() // exists > >>>>>>>>> KGroupedStream#count(Materialized) // exits > >>>>>>>>> KGroupedStream#count(Named) // added (makes sense to me) > >>>>>>>>> KGroupedStream#count(Named, Materialized) // added -- why? > >>>>>>>>> > >>>>>>>>> I would prefer to use `Materialized` to name the processor for > >>> this > >>>>>>>>> case, too. Can you elaborate on the motivation? > >>>>>>>>> > >>>>>>>>> > >>>>>>>>> -Matthias > >>>>>>>>> > >>>>>>>>> On 1/11/19 3:39 PM, Florian Hussonnois wrote: > >>>>>>>>>> Hi Guozhang, > >>>>>>>>>> > >>>>>>>>>> I have updated the PR as well as the KIP. I should add more > >> unit > >>>>> tests > >>>>>>> to > >>>>>>>>>> covers all new methods. > >>>>>>>>>> > >>>>>>>>>> However, I still have one test in failure. The reason is that > >>> using > >>>>>>>>>> Joined.name() in both potential repartition topic and processor > >>>> nodes > >>>>>>>>> leads > >>>>>>>>>> to topology-incompatible. > >>>>>>>>>> How should we deal with that ? > >>>>>>>>>> > >>>>>>>>>> Thanks, > >>>>>>>>>> > >>>>>>>>>> Le jeu. 10 janv. 2019 à 01:21, Guozhang Wang < > >> wangg...@gmail.com > >>>> > >>>> a > >>>>>>>>> écrit : > >>>>>>>>>> > >>>>>>>>>>> Hello Florian, > >>>>>>>>>>> > >>>>>>>>>>> Just checking if have read about my previous email and if you > >>> feel > >>>>>>> happy > >>>>>>>>>>> about it. We have the 2.2 KIP freeze deadline at 24th this > >>> month, > >>>>>>> while > >>>>>>>>> the > >>>>>>>>>>> PR itself is getting quite close. So it'll be great if we can > >>> get > >>>>> the > >>>>>>>>>>> agreement on it and get it into 2.2.0 release. > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> Guozhang > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> On Mon, Dec 17, 2018 at 2:39 PM Guozhang Wang < > >>> wangg...@gmail.com > >>>>> > >>>>>>>>> wrote: > >>>>>>>>>>> > >>>>>>>>>>>> Hi Florian / John, > >>>>>>>>>>>> > >>>>>>>>>>>> Just wanted to throw a couple minor thoughts on the current > >>>>> proposal: > >>>>>>>>>>>> > >>>>>>>>>>>> 1) Regarding the interface / function name, I'd propose we > >> call > >>>> the > >>>>>>>>>>>> interface `NamedOperation` which would be implemented by > >>>> Produced / > >>>>>>>>>>>> Consumed / Printed / Joined / Grouped / Suppressed (note I > >>>>>>>>> intentionally > >>>>>>>>>>>> exclude Materialized here since its semantics is quite), and > >>> have > >>>>> the > >>>>>>>>>>>> default class that implements `NamedOperation` as `Named`, > >>> which > >>>>>>> would > >>>>>>>>> be > >>>>>>>>>>>> used in our adding overload functions. The main reason is to > >>> have > >>>>>>>>>>>> consistency in naming. > >>>>>>>>>>>> > >>>>>>>>>>>> 2) As a minor tweak, I think it's better to use Joined.name() > >>> in > >>>>> both > >>>>>>>>> its > >>>>>>>>>>>> possibly generate repartition topic, as well as the map > >>> processor > >>>>>>> used > >>>>>>>>> for > >>>>>>>>>>>> group-by (currently this name is only used for the > >> repartition > >>>>>>> topic). > >>>>>>>>>>>> > >>>>>>>>>>>> > >>>>>>>>>>>> Florian: if you think this proposal makes sense, please feel > >>> free > >>>>> to > >>>>>>> go > >>>>>>>>>>>> ahead and update the PR; after we made a first pass on it and > >>>> feels > >>>>>>>>>>>> confident about it, we can go ahead with the VOTING process. > >>>> About > >>>>>>> the > >>>>>>>>>>>> implementation of 2) above, this may be out of your > >>>> implementation > >>>>>>>>> scope, > >>>>>>>>>>>> so feel free to leave it out side your PR while Bill who > >>>> originally > >>>>>>>>> worked > >>>>>>>>>>>> on the Grouped KIP can make a follow-up PR for it. > >>>>>>>>>>>> > >>>>>>>>>>>> Guozhang > >>>>>>>>>>>> > >>>>>>>>>>>> On Fri, Dec 14, 2018 at 9:43 PM Guozhang Wang < > >>>> wangg...@gmail.com> > >>>>>>>>> wrote: > >>>>>>>>>>>> > >>>>>>>>>>>>> Hello Florian, > >>>>>>>>>>>>> > >>>>>>>>>>>>> Really appreciate you for your patience. > >>>>>>>>>>>>> > >>>>>>>>>>>>> I know that we've discussed about the approach to adding > >>>>> overloaded > >>>>>>>>>>>>> functions and rejected it early on. But looking deeper into > >>> the > >>>>>>>>> current PR > >>>>>>>>>>>>> I realized that this approach has a danger of great API > >>>> confusions > >>>>>>> to > >>>>>>>>> users > >>>>>>>>>>>>> (I tried to explain my thoughts in the PR, but it was not > >> very > >>>>>>> clear) > >>>>>>>>> --- > >>>>>>>>>>>>> the basic idea is that, today we already have a few existing > >>>>> control > >>>>>>>>>>>>> classes including Grouped, Joined, Suppressed that allow > >> users > >>>> to > >>>>>>>>> specify > >>>>>>>>>>>>> serdes etc, while also a "name" which can then be used to > >>> define > >>>>> the > >>>>>>>>>>>>> processor name / internal topic names in the topology (the > >>>> static > >>>>>>>>> function > >>>>>>>>>>>>> names are not consistent, which I think we should fix as > >>> well). > >>>>> And > >>>>>>>>> Named > >>>>>>>>>>>>> interface, by extending the lambda function interfaces like > >>>>>>>>> ValueJoiner / > >>>>>>>>>>>>> Predicate etc opens the door for another way to specify the > >>>> names > >>>>>>>>> again. > >>>>>>>>>>>>> > >>>>>>>>>>>>> So in order to achieve consistency, we are left with > >> generally > >>>> two > >>>>>>>>>>>>> options: > >>>>>>>>>>>>> > >>>>>>>>>>>>> 1) only allow users to specify names via the lambda > >> interfaces > >>>>> that > >>>>>>>>>>>>> extends Named interface. This means we'd better remove the > >>>> naming > >>>>>>>>> mechanism > >>>>>>>>>>>>> from the existing control objects to keep consistency. > >>>>>>>>>>>>> > >>>>>>>>>>>>> 2) only allow users to specify names via control classes, > >> and > >>> we > >>>>>>>>>>>>> introduce a new class (Named) for those which do not have > >> one > >>>> yet > >>>>>>> --- > >>>>>>>>> this > >>>>>>>>>>>>> leads to the overloaded functions. > >>>>>>>>>>>>> > >>>>>>>>>>>>> I did a quick count on the num.of overloaded functions, and > >>>>> summing > >>>>>>>>> from > >>>>>>>>>>>>> KTable (8) / KStream (15) / KGroupedStream (6) / > >> KGroupedTable > >>>>> (6) / > >>>>>>>>>>>>> TimeWindowedKStream (6) / SessionWindowedKStream (6) we got > >>>> about > >>>>> 47 > >>>>>>>>>>>>> overloaded functions (our guess was pretty close!) -- note > >>> this > >>>> is > >>>>>>>>> based on > >>>>>>>>>>>>> John's proposal that we can let existing Grouped / Joined to > >>>>> extend > >>>>>>>>> Named > >>>>>>>>>>>>> and hence we only need overloaded functions with a default > >>>>>>>>> NamedOperation > >>>>>>>>>>>>> for those operators that do not have a control classes > >>> already. > >>>>>>>>>>>>> > >>>>>>>>>>>>> Thinking about this approach I feel it is not too bad > >> compared > >>>>> with > >>>>>>>>>>>>> either 1) above, which would require us to deprecate lot of > >>>> public > >>>>>>>>>>>>> functions around name(), or having a mixed mechanism for > >>> naming, > >>>>>>> which > >>>>>>>>>>>>> could lead to very confusing behavior to users. > >> Additionally, > >>>> for > >>>>>>> most > >>>>>>>>>>>>> users who would only want to specify the names for those > >>>> stateful > >>>>>>>>>>>>> operations which have internal topics / state stores and > >> hence > >>>> are > >>>>>>>>> more > >>>>>>>>>>>>> keen to upgrade compatibility, those added overloads would > >> be > >>>>>>>>> not-often > >>>>>>>>>>>>> used functions for them anyways. And by letting existing > >>> control > >>>>>>>>> classes to > >>>>>>>>>>>>> extend Named, we can have a unified method name for static > >>>>>>>>> constructor as > >>>>>>>>>>>>> well. > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>> Guozhang > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>> On Fri, Dec 14, 2018 at 10:24 AM John Roesler < > >>>> j...@confluent.io> > >>>>>>>>> wrote: > >>>>>>>>>>>>> > >>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Sorry about the run-around of rejecting the original > >>> proposal, > >>>>>>>>>>>>>> only to return to it later on. Hopefully, it's more > >>> encouraging > >>>>>>>>>>>>>> than frustrating that we're coming around to your initial > >> way > >>>> of > >>>>>>>>>>>>>> thinking. > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> Thanks! > >>>>>>>>>>>>>> -John > >>>>>>>>>>>>>> > >>>>>>>>>>>>>> On Thu, Dec 13, 2018 at 4:28 PM Florian Hussonnois < > >>>>>>>>>>>>>> fhussonn...@gmail.com> > >>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>> > >>>>>>>>>>>>>>> Hi all, > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> Thanks again. I agree with your propositions. > >>>>>>>>>>>>>>> Also IMHO, overloading all methods (filter, map) to > >> accept a > >>>> new > >>>>>>>>>>>>>> control > >>>>>>>>>>>>>>> object seems to provide a more natural development > >>> experience > >>>>> for > >>>>>>>>>>>>>> users. > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> Actually, this was the first proposition for this KIP, but > >>> we > >>>>> have > >>>>>>>>>>>>>> rejected > >>>>>>>>>>>>>>> it because this solution led to adding a lot of new > >> methods. > >>>>>>>>>>>>>>> As you mentioned it, the API has evolve since the creation > >>> of > >>>>> this > >>>>>>>>>>>>>> KIP - > >>>>>>>>>>>>>>> some existing control objects already allow to customize > >>>>> internal > >>>>>>>>>>>>>> names. We > >>>>>>>>>>>>>>> should so keep on that strategy. > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> If everyone is OK with that, I will update the KIP and the > >>> PR > >>>>>>>>>>>>>> accordingly; > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> Thanks. > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> Le jeu. 13 déc. 2018 à 18:08, John Roesler < > >>> j...@confluent.io > >>>>> > >>>>> a > >>>>>>>>>>>>>> écrit : > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Hi again, all, > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Matthias, I agree with you. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Florian, thanks for your response. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> I think your proposal is the best way to address the ask > >>> for > >>>>>>> hiding > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>> name() getter. But I'd like to question that ask and > >>> instead > >>>>>>>>>>>>>> propose that > >>>>>>>>>>>>>>>> we just make the name() getter part of the public API. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> The desire to "hide" the getters causes a lot of > >> complexity > >>>> in > >>>>>>> our > >>>>>>>>>>>>>> code > >>>>>>>>>>>>>>>> base, and it will become completely impractical with the > >>>> mixin > >>>>>>>>>>>>>> strategy > >>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>> Named. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> If we were to switch strategies back to mixing Named in > >> to > >>>> the > >>>>>>>>>>>>>> control > >>>>>>>>>>>>>>>> objects rather than the functions, then the path forward > >>>>> becomes > >>>>>>>>>>>>>> quite > >>>>>>>>>>>>>>>> clear. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> On the other hand, it seems harmless for anyone who wants > >>> to > >>>> be > >>>>>>>>>>>>>> able to > >>>>>>>>>>>>>>>> query the name from a control object after setting it, so > >>> my > >>>>> vote > >>>>>>>>>>>>>> would > >>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>> simply to keep the Named interface as: > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> public interface Named<T extends Named<T>> { > >>>>>>>>>>>>>>>> String name(); > >>>>>>>>>>>>>>>> T withName(String name); > >>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Under this proposal, we only mix Named in to the control > >>>>> objects, > >>>>>>>>>>>>>> which > >>>>>>>>>>>>>>>> means we have no need of default implementations anymore > >>>>> (because > >>>>>>>>>>>>>> we can > >>>>>>>>>>>>>>>> update all the control objects concurrently with adding > >>> this > >>>>>>>>>>>>>> interface to > >>>>>>>>>>>>>>>> them). > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> This does hinge on switching over to a > >> control-object-only > >>>>>>>>> strategy, > >>>>>>>>>>>>>>> which > >>>>>>>>>>>>>>>> introduces the need to add about 50 new control object > >>>> classes, > >>>>>>>>>>>>>> which > >>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>> only serve to implement Named. As a middle ground, maybe > >> we > >>>>> could > >>>>>>>>>>>>>> just > >>>>>>>>>>>>>>> add > >>>>>>>>>>>>>>>> one generic control object class, like: > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> public class NamedOperation implements > >>> Named<NamedOperation> > >>>> { > >>>>>>>>>>>>>>>> private final String name; > >>>>>>>>>>>>>>>> private NamedOperation(final String name) { this.name > >> = > >>>>> name; > >>>>>>> } > >>>>>>>>>>>>>>>> public static NamedOperation name(final String name) { > >>>>>>>>>>>>>>>> return new NamedOperation(name); > >>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>> public String name() { return name; } > >>>>>>>>>>>>>>>> public NamedOperation withName(final String name) { > >>>>>>>>>>>>>>>> return new NamedOperation(name); > >>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> And then, we'd add overloads for all the methods that > >> don't > >>>>> have > >>>>>>>>>>>>>> control > >>>>>>>>>>>>>>>> objects already (for example, filter() ): > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> // existing > >>>>>>>>>>>>>>>> KStream<K, V> filter(Predicate<? super K, ? super V> > >>>>> predicate); > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> // new > >>>>>>>>>>>>>>>> KStream<K, V> filter(Predicate<? super K, ? super V> > >>>> predicate, > >>>>>>>>>>>>>>>> NamedOperation named); > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Additionally, in regard to Matthias's point about > >> existing > >>>>>>> control > >>>>>>>>>>>>>>> objects > >>>>>>>>>>>>>>>> with naming semantics, they would extend Named (but not > >>>>>>>>>>>>>> NamedOperation) > >>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>> uniformity. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> You provided a good approach to hide the getter with your > >>>>>>>>>>>>>> SettableName > >>>>>>>>>>>>>>>> class; I think what you proposed is the only way we could > >>>> hide > >>>>>>> the > >>>>>>>>>>>>>> name. > >>>>>>>>>>>>>>>> In the end, though, it's a lot of complexity added > >> (control > >>>>>>> object > >>>>>>>>>>>>>> class > >>>>>>>>>>>>>>>> hierarchy, inheritance, mutable state, internal casting) > >>> for > >>>>>>>>>>>>>> something of > >>>>>>>>>>>>>>>> dubious value: to be able to hide the name from someone > >>>> *after > >>>>>>> they > >>>>>>>>>>>>>>>> themselves have set it*. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Although it'll be a pain, perhaps Matthias's suggestion > >> to > >>>>>>>>>>>>>> enumerate all > >>>>>>>>>>>>>>>> the API methods is the best way to be sure we all agree > >> on > >>>>> what's > >>>>>>>>>>>>>> going > >>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>> happen. > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> Thanks again for wrangling with this issue, > >>>>>>>>>>>>>>>> -John > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> On Thu, Dec 13, 2018 at 9:03 AM Matthias J. Sax < > >>>>>>>>>>>>>> matth...@confluent.io> > >>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> Just catching up on this discussion. > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> My overall personal take is, that I am not a big fan of > >>> the > >>>>>>>>>>>>>> interface > >>>>>>>>>>>>>>>>> `Named` that is used as a factory. I would rather prefer > >>> to > >>>>> add > >>>>>>> a > >>>>>>>>>>>>>>>>> control object parameter to all methods that don't have > >>> one > >>>>> yet. > >>>>>>>>>>>>>> This > >>>>>>>>>>>>>>>>> KIP was started a while ago, and we added new naming > >>>>>>> capabilities > >>>>>>>>>>>>>> in > >>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>> meantime. Guozhang's example in the PR comment about > >>> naming > >>>> in > >>>>>>>>>>>>>>>>> stream-stream join shows, that we might end up in a > >>>> confusion > >>>>>>>>>>>>>> situation > >>>>>>>>>>>>>>>>> for users if we use `Named`. Also, in 2.1, user can > >>> already > >>>>> name > >>>>>>>>>>>>>> as > >>>>>>>>>>>>>>>>> repartition-/changelog-topics and stores. Thus, KIP-307 > >>>> boils > >>>>>>>>>>>>>> down to > >>>>>>>>>>>>>>>>> provide non-functional naming? > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> Hence, for all methods that allow to specify names > >>> already, > >>>> I > >>>>>>>>>>>>>> don't see > >>>>>>>>>>>>>>>>> any reason to change them, but use the existing API to > >>> also > >>>>> name > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>> processor(s) instead of allowing uses to specify a new > >>> name. > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> About the inconsistency in method naming. I agree, that > >>> `as` > >>>>> is > >>>>>>>>>>>>>> very > >>>>>>>>>>>>>>>>> generic and maybe not the best choice. > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> I think it might be helpful, to have a table overview in > >>> the > >>>>>>> KIP, > >>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>> list all existing static/non-static methods that allow > >> to > >>>>>>> specify > >>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>> name, plus a columns with the new suggested naming for > >>> those > >>>>>>>>>>>>>> methods? > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> Thoughts? > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> -Matthias > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> On 12/12/18 12:45 AM, Florian Hussonnois wrote: > >>>>>>>>>>>>>>>>>> Thank you very much for your feedbacks. > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> Currently, there is still lot of discussions regarding > >>> the > >>>>>>> Named > >>>>>>>>>>>>>>>>> interface. > >>>>>>>>>>>>>>>>>> On the one hand we should provided consistency over the > >>>>> stream > >>>>>>>>>>>>>> API > >>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>> on > >>>>>>>>>>>>>>>>>> the other hand we should not break the semantic as John > >>>> point > >>>>>>>>>>>>>> it up. > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> Guozhang, I'm sorry, but I'm little bit confused, > >> maybe I > >>>>>>> missed > >>>>>>>>>>>>>>>>> something. > >>>>>>>>>>>>>>>>>> In your comment you have suggested that : > >>>>>>>>>>>>>>>>>> * Produced/Consumed/Suppressed should extends Named > >>>>>>>>>>>>>>>>>> * Named should have a private-package method to get the > >>>>>>>>>>>>>> specified > >>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>> name internally (processorName()) > >>>>>>>>>>>>>>>>>> * Finally we should end up with something like : Named > >>> -> > >>>>> XXX > >>>>>>>>>>>>>> -> > >>>>>>>>>>>>>>>>>> XXXInternal or Named -> Produced -> ProducedInternal > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> The objective behind that is to : > >>>>>>>>>>>>>>>>>> * consolidate the internal method processorName() > >>>>>>>>>>>>>>>>>> * consolidate the method withName that exists now > >>> existing > >>>>> into > >>>>>>>>>>>>>>>> Produced, > >>>>>>>>>>>>>>>>>> Consumed and Suppressed. > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> But, Named is an interface so we can't define a > >>>>> private-package > >>>>>>>>>>>>>>> method > >>>>>>>>>>>>>>>> on > >>>>>>>>>>>>>>>>>> it. Also, for example Produced and ProducedInternal are > >>> not > >>>>> in > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>> same > >>>>>>>>>>>>>>>>>> package so having a private-package method doesn't > >> really > >>>>> help. > >>>>>>>>>>>>>>>>>> In addition, if we add the withName method into Named > >>>>> interface > >>>>>>>>>>>>>> this > >>>>>>>>>>>>>>>> can > >>>>>>>>>>>>>>>>>> become confusing for developers because action > >> interfaces > >>>>>>>>>>>>>>> (ValueMapper, > >>>>>>>>>>>>>>>>>> Reducer, etc) extend it. > >>>>>>>>>>>>>>>>>> The interface would look like : > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> public interface Named<T extends Named<T>> { > >>>>>>>>>>>>>>>>>> default String name() { > >>>>>>>>>>>>>>>>>> return null; > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> default Named<T> withName(final String name) { > >>>>>>>>>>>>>>>>>> return null; > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> ... > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> So maybe instead of adding another method to Named we > >>> could > >>>>>>>>>>>>>> create a > >>>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>> package-private class that could be extended by > >>>>>>>>>>>>>>>>>> Produced/Consumed/Joined/Suppressed. For exemple, > >>>>>>>>>>>>>>>>>> class SettableName<T extends SettableName<T>> > >> implements > >>>>> Named > >>>>>>> { > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> protected String processorName; > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> SettableName(final SettableName settable) { > >>>>>>>>>>>>>>>>>> this(Objects.requireNonNull(settable, "settable > >>>> can't > >>>>>>> be > >>>>>>>>>>>>>>>>>> null").name()); > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> SettableName(final String processorName) { > >>>>>>>>>>>>>>>>>> this.processorName = processorName; > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> @Override > >>>>>>>>>>>>>>>>>> public String name() { > >>>>>>>>>>>>>>>>>> return processorName; > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> public T withName(final String processorName) { > >>>>>>>>>>>>>>>>>> this.processorName = processorName; > >>>>>>>>>>>>>>>>>> return (T)this; > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> In that way, we will get : public class Produced > >>> implements > >>>>>>>>>>>>>>>>>> SettableName<Produced> { ... > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> WDYT? > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> Le mar. 11 déc. 2018 à 02:46, Guozhang Wang < > >>>>>>> wangg...@gmail.com> > >>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>> écrit : > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> I had one meta comment on the PR: > >>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>> https://github.com/apache/kafka/pull/5909#discussion_r240447153 > >>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> On Mon, Dec 10, 2018 at 5:22 PM John Roesler < > >>>>>>>>>>>>>> j...@confluent.io> > >>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> I hope it's ok if I ask a few questions at this late > >>>>> stage... > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Comment 1 ====== > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> It seems like the proposal is to add a new "Named" > >>>>> interface > >>>>>>>>>>>>>> that > >>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>> intended to be mixed in with the existing API objects > >>> at > >>>>>>>>>>>>>> various > >>>>>>>>>>>>>>>>> points. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Just to preface some of my comments, it looks like > >> your > >>>> KIP > >>>>>>>>>>>>>> was > >>>>>>>>>>>>>>>> created > >>>>>>>>>>>>>>>>>>>> quite a while ago, so the API may have changed > >> somewhat > >>>>> since > >>>>>>>>>>>>>> you > >>>>>>>>>>>>>>>>>>> started. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> As I see the API, there are a few different kinds of > >>> DSL > >>>>>>>>>>>>>> method > >>>>>>>>>>>>>>>>>>> arguments: > >>>>>>>>>>>>>>>>>>>> * functions: things like Initializer, Aggregator, > >>>>>>> ValueJoiner, > >>>>>>>>>>>>>>>>>>>> ForEachAction... All of these are essentially > >>>>>>> Streams-flavored > >>>>>>>>>>>>>>>> Function > >>>>>>>>>>>>>>>>>>>> interfaces with different arities, type bounds, and > >>>>>>> semantics. > >>>>>>>>>>>>>>>>>>>> * config objects: things like Produced, Consumed, > >>> Joined, > >>>>>>>>>>>>>>> Grouped... > >>>>>>>>>>>>>>>>>>> These > >>>>>>>>>>>>>>>>>>>> are containers for configurations, where the target > >> of > >>>> the > >>>>>>>>>>>>>>>>> configuration > >>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>> the operation itself > >>>>>>>>>>>>>>>>>>>> * raw configurations: things like a raw topic-name > >>> string > >>>>> and > >>>>>>>>>>>>>>>>>>> Materialized: > >>>>>>>>>>>>>>>>>>>> These are configurations for operations that have no > >>>> config > >>>>>>>>>>>>>> object, > >>>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>>>>>> various reasons, we didn't make one. The > >> distinguishing > >>>>>>>>>>>>>> feature is > >>>>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>> target of the configuration is not the operation > >>> itself, > >>>>> but > >>>>>>>>>>>>>> some > >>>>>>>>>>>>>>>>> aspect > >>>>>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>>> it. For example, in Materialized, we are not setting > >>> the > >>>>>>>>>>>>>> caching > >>>>>>>>>>>>>>>>> behavior > >>>>>>>>>>>>>>>>>>>> of, for example, an aggregation; we're setting the > >>>> caching > >>>>>>>>>>>>>> behavior > >>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>> materialized state store attached to the aggregation. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> It seems like choosing to mix the Named interface in > >>> with > >>>>> the > >>>>>>>>>>>>>>>> functions > >>>>>>>>>>>>>>>>>>> has > >>>>>>>>>>>>>>>>>>>> a couple of unfortunate side-effects: > >>>>>>>>>>>>>>>>>>>> * Aggregator is not the only function passed to any > >> of > >>>> the > >>>>>>>>>>>>>> relevant > >>>>>>>>>>>>>>>>>>>> aggregate methods, so it seems a little arbitrary to > >>> pick > >>>>>>> that > >>>>>>>>>>>>>>>> function > >>>>>>>>>>>>>>>>>>>> over Initializer or Merger. > >>>>>>>>>>>>>>>>>>>> * As you noted, branch() takes an array of Predicate, > >>> so > >>>> we > >>>>>>>>>>>>>> just > >>>>>>>>>>>>>>>> ignore > >>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>> provided name(s), even though Predicate names are > >> used > >>>>>>>>>>>>>> elsewhere. > >>>>>>>>>>>>>>>>>>>> * Not all things that we want to name have function > >>>>>>> arguments, > >>>>>>>>>>>>>>>> notably > >>>>>>>>>>>>>>>>>>>> source and sink, so we'd switch paradigms and use the > >>>>> config > >>>>>>>>>>>>>> object > >>>>>>>>>>>>>>>>>>>> instead. > >>>>>>>>>>>>>>>>>>>> * Adding an extra method to the function interfaces > >>> means > >>>>>>> that > >>>>>>>>>>>>>>> those > >>>>>>>>>>>>>>>>> are > >>>>>>>>>>>>>>>>>>> no > >>>>>>>>>>>>>>>>>>>> longer SAM interfaces. You proposed to add a default > >>>>>>>>>>>>>>> implementation, > >>>>>>>>>>>>>>>> so > >>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>> could still pass a lambda if we don't want to set the > >>>> name, > >>>>>>>>>>>>>> but if > >>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>> *do* > >>>>>>>>>>>>>>>>>>>> want to set the name, we can no longer use lambdas. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> I think the obvious other choice would be to mix > >> Named > >>> in > >>>>>>>>>>>>>> with the > >>>>>>>>>>>>>>>>> config > >>>>>>>>>>>>>>>>>>>> objects instead, but this has one main downside of > >> its > >>>>> own... > >>>>>>>>>>>>>>>>>>>> * not every operator we wish to name has a config > >>>> object. I > >>>>>>>>>>>>>> don't > >>>>>>>>>>>>>>>> know > >>>>>>>>>>>>>>>>> if > >>>>>>>>>>>>>>>>>>>> everyone involved is comfortable with adding a config > >>>>> object > >>>>>>>>>>>>>> to > >>>>>>>>>>>>>>> every > >>>>>>>>>>>>>>>>>>>> operator that's missing one. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Personally, I favor moving toward a more consistent > >>> state > >>>>>>>>>>>>>> that's > >>>>>>>>>>>>>>>>> forward > >>>>>>>>>>>>>>>>>>>> compatible with any further changes we wish to make. > >> I > >>>>>>>>>>>>>> *think* that > >>>>>>>>>>>>>>>>>>> giving > >>>>>>>>>>>>>>>>>>>> every operator two forms (one with no config and one > >>>> with a > >>>>>>>>>>>>>> config > >>>>>>>>>>>>>>>>>>> object) > >>>>>>>>>>>>>>>>>>>> would be such an API. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Comment 2 ========= > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Finally, just a minor comment: the static method in > >>> Named > >>>>>>>>>>>>>> wouldn't > >>>>>>>>>>>>>>>> work > >>>>>>>>>>>>>>>>>>>> properly as defined. Assuming that we mix Named in > >> with > >>>>>>>>>>>>>> Produced, > >>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>>>>>> example, we'd need to be able to use it like: > >>>>>>>>>>>>>>>>>>>>> kStream.to("out", Produced.with("myOut")) > >>>>>>>>>>>>>>>>>>>> This doesn't work because with() returns a Named, but > >>> we > >>>>> need > >>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>> Produced. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> We can pull off a builder method in the interface, > >> but > >>>> not > >>>>> a > >>>>>>>>>>>>>> static > >>>>>>>>>>>>>>>>>>> method. > >>>>>>>>>>>>>>>>>>>> To define a builder method in the interface that > >>> returns > >>>> an > >>>>>>>>>>>>>>> instance > >>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>> concrete subtype, you have to use the "curiously > >>>> recurring > >>>>>>>>>>>>>> generic" > >>>>>>>>>>>>>>>>>>>> pattern. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> It would look like: > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> public interface Named<N extends Named<N>> { > >>>>>>>>>>>>>>>>>>>> String name(); > >>>>>>>>>>>>>>>>>>>> N withName(String name); > >>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> You can see where the name of the pattern comes from > >> ;) > >>>>>>>>>>>>>>>>>>>> An implementation would then look like: > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> public class Produced implements Named<Produced> { > >>>>>>>>>>>>>>>>>>>> String name() { return name; } > >>>>>>>>>>>>>>>>>>>> Produced withName(final String name) { this.name = > >>>> name; > >>>>>>>>>>>>>> return > >>>>>>>>>>>>>>>>> this; > >>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Note that the generic parameter gets filled in > >> properly > >>>> in > >>>>>>> the > >>>>>>>>>>>>>>>>>>> implementing > >>>>>>>>>>>>>>>>>>>> class, so that you get the right return type out. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> It doesn't work at all with a static factory method > >> at > >>>> the > >>>>>>>>>>>>>>> interface > >>>>>>>>>>>>>>>>>>> level, > >>>>>>>>>>>>>>>>>>>> so it would be up to Produced to define a static > >>> factory > >>>> if > >>>>>>> it > >>>>>>>>>>>>>>> wants > >>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>> present one. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> ====== > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Those are my two feedbacks! > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> I hope you find this helpful, rather than > >> frustrating. > >>>> I'm > >>>>>>>>>>>>>> sorry I > >>>>>>>>>>>>>>>>> didn't > >>>>>>>>>>>>>>>>>>>> get a chance to comment sooner. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> Thanks for the KIP, I think it will be much nicer to > >> be > >>>>> able > >>>>>>>>>>>>>> to > >>>>>>>>>>>>>>> name > >>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>> processor nodes. > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> -John > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> On Tue, Nov 27, 2018 at 6:34 PM Guozhang Wang < > >>>>>>>>>>>>>> wangg...@gmail.com> > >>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> I've made a pass over the PR. There are some > >> comments > >>>> that > >>>>>>>>>>>>>> are > >>>>>>>>>>>>>>>> related > >>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>> the function names which may be affecting the KIP > >> wiki > >>>>> page, > >>>>>>>>>>>>>> but > >>>>>>>>>>>>>>>>>>> overall > >>>>>>>>>>>>>>>>>>>> I > >>>>>>>>>>>>>>>>>>>>> think it looks good already. > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> Guozhang > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> On Fri, Nov 16, 2018 at 4:21 PM Guozhang Wang < > >>>>>>>>>>>>>> wangg...@gmail.com > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> Thanks Florian! I will take a look at the PR. > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> On Mon, Nov 12, 2018 at 2:44 PM Florian Hussonnois > >> < > >>>>>>>>>>>>>>>>>>>>> fhussonn...@gmail.com> > >>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>> Hi Matthias, > >>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>> Sorry I was absent for a while. I have started a > >> new > >>>> PR > >>>>>>>>>>>>>> for this > >>>>>>>>>>>>>>>>>>> KIP. > >>>>>>>>>>>>>>>>>>>> It > >>>>>>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>>>>> still in progress for now. I'm working on it. > >>>>>>>>>>>>>>>>>>>>>>> https://github.com/apache/kafka/pull/5909 > >>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>> Le ven. 19 oct. 2018 à 20:13, Matthias J. Sax < > >>>>>>>>>>>>>>>>>>> matth...@confluent.io> > >>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>> écrit : > >>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>> What is the status of this KIP? > >>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>> -Matthias > >>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>> On 7/19/18 5:17 PM, Guozhang Wang wrote: > >>>>>>>>>>>>>>>>>>>>>>>>> Hello Florian, > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> Sorry for being late... Found myself keep > >>>> apologizing > >>>>>>>>>>>>>> for late > >>>>>>>>>>>>>>>>>>>>> replies > >>>>>>>>>>>>>>>>>>>>>>>>> these days. But I do want to push this KIP's > >>>> progress > >>>>>>>>>>>>>> forward > >>>>>>>>>>>>>>>>>>> as I > >>>>>>>>>>>>>>>>>>>>>>> see it > >>>>>>>>>>>>>>>>>>>>>>>>> very important and helpful feature for > >>>> extensibility. > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> About the exceptions, I've gone through them and > >>>>>>>>>>>>>> hopefully it > >>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>> an > >>>>>>>>>>>>>>>>>>>>>>>>> exhaustive list: > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> 1. KTable#toStream() > >>>>>>>>>>>>>>>>>>>>>>>>> 2. KStream#merge(KStream) > >>>>>>>>>>>>>>>>>>>>>>>>> 3. KStream#process() / transform() / > >>>> transformValues() > >>>>>>>>>>>>>>>>>>>>>>>>> 4. KGroupedTable / KGroupedStream#count() > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> Here's my reasoning: > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> * It is okay not letting users to override the > >>> name > >>>>> for > >>>>>>>>>>>>>> 1/2, > >>>>>>>>>>>>>>>>>>> since > >>>>>>>>>>>>>>>>>>>>>>> they > >>>>>>>>>>>>>>>>>>>>>>>> are > >>>>>>>>>>>>>>>>>>>>>>>>> too trivial to be useful for debugging, plus > >> their > >>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>> names > >>>>>>>>>>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>>>>>>>>>>> not determine any related topic / store names. > >>>>>>>>>>>>>>>>>>>>>>>>> * For 3, I'd vote for adding overloaded > >> functions > >>>> with > >>>>>>>>>>>>>> Named. > >>>>>>>>>>>>>>>>>>>>>>>>> * For 4, if users really want to name the > >>> processor > >>>>> she > >>>>>>>>>>>>>> can > >>>>>>>>>>>>>>> call > >>>>>>>>>>>>>>>>>>>>>>>>> aggregate() instead, so I think it is okay to > >> skip > >>>>> this > >>>>>>>>>>>>>> case. > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> Guozhang > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> On Fri, Jul 6, 2018 at 3:06 PM, Florian > >>> Hussonnois < > >>>>>>>>>>>>>>>>>>>>>>>> fhussonn...@gmail.com> > >>>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> Hi, > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> The option #3 seems to be a good alternative > >> and > >>> I > >>>>> find > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>> API > >>>>>>>>>>>>>>>>>>>>> more > >>>>>>>>>>>>>>>>>>>>>>>>>> elegant (thanks John). > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> But, we still have the need to overload some > >>>> methods > >>>>>>>>>>>>>> either > >>>>>>>>>>>>>>>>>>>> because > >>>>>>>>>>>>>>>>>>>>>>>> they do > >>>>>>>>>>>>>>>>>>>>>>>>>> not accept an action instance or because they > >> are > >>>>>>>>>>>>>> translated > >>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>> multiple > >>>>>>>>>>>>>>>>>>>>>>>>>> processors. > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> For example, this is the case for methods > >>> branch() > >>>>> and > >>>>>>>>>>>>>>> merge(). > >>>>>>>>>>>>>>>>>>>> We > >>>>>>>>>>>>>>>>>>>>>>> could > >>>>>>>>>>>>>>>>>>>>>>>>>> introduce a new interface Named (or maybe a > >>>> different > >>>>>>>>>>>>>> name ?) > >>>>>>>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>> method > >>>>>>>>>>>>>>>>>>>>>>>>>> name(). All action interfaces could extend this > >>> one > >>>>> to > >>>>>>>>>>>>>>>>>>> implement > >>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>> option > >>>>>>>>>>>>>>>>>>>>>>>>>> 3). > >>>>>>>>>>>>>>>>>>>>>>>>>> This would result by having the following > >>> overloads > >>>>> : > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> Stream<K, V> merge(final Named name, final > >>>> KStream<K, > >>>>>>> V> > >>>>>>>>>>>>>>>>>>> stream); > >>>>>>>>>>>>>>>>>>>>>>>>>> KStream<K, V>[] branch(final Named name, final > >>>>>>>>>>>>>> Predicate<? > >>>>>>>>>>>>>>>>>>> super > >>>>>>>>>>>>>>>>>>>>> K, ? > >>>>>>>>>>>>>>>>>>>>>>>> super > >>>>>>>>>>>>>>>>>>>>>>>>>> V>... predicates) > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> N.B : The list above is not exhaustive > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> --------- > >>>>>>>>>>>>>>>>>>>>>>>>>> user's code will become : > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> KStream<String, Integer> stream = > >>>>>>>>>>>>>>>>>>> builder.stream("test"); > >>>>>>>>>>>>>>>>>>>>>>>>>> KStream<String, Integer>[] branches = > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>> stream.branch(Named.with("BRANCH-STREAM-ON-VALUE"), > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>> Predicate.named("STREAM-PAIR-VALUE", > >>>>>>>>>>>>>> (k, v) > >>>>>>>>>>>>>>> -> > >>>>>>>>>>>>>>>>>>> v > >>>>>>>>>>>>>>>>>>>> % > >>>>>>>>>>>>>>>>>>>>> 2 > >>>>>>>>>>>>>>>>>>>>>>> == > >>>>>>>>>>>>>>>>>>>>>>>>>> 0), > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>> Predicate.named("STREAM-IMPAIR-VALUE", > >>>>>>>>>>>>>> (k, v) > >>>>>>>>>>>>>>>>>>> -> > >>>>>>>>>>>>>>>>>>>> v > >>>>>>>>>>>>>>>>>>>>> % > >>>>>>>>>>>>>>>>>>>>>>> 2 > >>>>>>>>>>>>>>>>>>>>>>>> != > >>>>>>>>>>>>>>>>>>>>>>>>>> 0)); > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> branches[0].to("pair"); > >>>>>>>>>>>>>>>>>>>>>>>>>> branches[1].to("impair"); > >>>>>>>>>>>>>>>>>>>>>>>>>> --------- > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> This is a mix of the options 3) and 1) > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> Le ven. 6 juil. 2018 à 22:58, Guozhang Wang < > >>>>>>>>>>>>>>>>>>> wangg...@gmail.com> > >>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>> écrit : > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> Hi folks, just to summarize the options we > >> have > >>> so > >>>>>>> far: > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> 1) Add a new "as" for KTable / KStream, plus > >>>> adding > >>>>>>> new > >>>>>>>>>>>>>>> fields > >>>>>>>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>>>>>>>>>>>>> operators-returns-void control objects (the > >>>> current > >>>>>>>>>>>>>> wiki's > >>>>>>>>>>>>>>>>>>>>>>> proposal). > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> Pros: no more overloads. > >>>>>>>>>>>>>>>>>>>>>>>>>>> Cons: a bit departing with the current > >>> high-level > >>>>> API > >>>>>>>>>>>>>> design > >>>>>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>> DSL, > >>>>>>>>>>>>>>>>>>>>>>>>>>> plus, the inconsistency between > >>>>> operators-returns-void > >>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>>>>>>>> operators-not-return-voids. > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> 2) Add overloaded functions for all operators, > >>>> that > >>>>>>>>>>>>>> accepts > >>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>>>>>>>> control > >>>>>>>>>>>>>>>>>>>>>>>>>>> object "Described". > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> Pros: consistent with current APIs. > >>>>>>>>>>>>>>>>>>>>>>>>>>> Cons: lots of overloaded functions to add. > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> 3) Add another default function in the > >> interface > >>>>>>>>>>>>>> (thank you > >>>>>>>>>>>>>>>>>>> J8!) > >>>>>>>>>>>>>>>>>>>>> as > >>>>>>>>>>>>>>>>>>>>>>>> John > >>>>>>>>>>>>>>>>>>>>>>>>>>> proposed. > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> Pros: no overloaded functions, no "Described". > >>>>>>>>>>>>>>>>>>>>>>>>>>> Cons: do we lose lambda functions really > >> (seems > >>>> not > >>>>> if > >>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>> provide > >>>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>>>> "named" > >>>>>>>>>>>>>>>>>>>>>>>>>>> for each func)? Plus "Described" may be more > >>>>>>> extensible > >>>>>>>>>>>>>>> than a > >>>>>>>>>>>>>>>>>>>>>>> single > >>>>>>>>>>>>>>>>>>>>>>>>>>> `String`. > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> My principle of considering which one is > >> better > >>>>>>> depends > >>>>>>>>>>>>>>>>>>>> primarily > >>>>>>>>>>>>>>>>>>>>> on > >>>>>>>>>>>>>>>>>>>>>>>> "how > >>>>>>>>>>>>>>>>>>>>>>>>>>> to make advanced users easily use the > >> additional > >>>>> API, > >>>>>>>>>>>>>> while > >>>>>>>>>>>>>>>>>>>>> keeping > >>>>>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>>> hidden from normal users who do not care at > >>> all". > >>>>> For > >>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>>>>>> purpose I > >>>>>>>>>>>>>>>>>>>>>>>>>> think > >>>>>>>>>>>>>>>>>>>>>>>>>>> 3) > 1) > 2). > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> One caveat though, is that changing the > >>> interface > >>>>>>>>>>>>>> would not > >>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>>> binary-compatible though source-compatible, > >>> right? > >>>>>>> I.e. > >>>>>>>>>>>>>>> users > >>>>>>>>>>>>>>>>>>>> need > >>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>> recompile their code though no changes needed. > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> Another note: for 3), if we really want to > >> keep > >>>>>>>>>>>>>>> extensibility > >>>>>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>>>>>>>>> Described > >>>>>>>>>>>>>>>>>>>>>>>>>>> we could do sth. like: > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> --------- > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> public interface Predicate<K, V> { > >>>>>>>>>>>>>>>>>>>>>>>>>>> // existing method > >>>>>>>>>>>>>>>>>>>>>>>>>>> boolean test(final K key, final V value); > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> // new default method adds the ability to > >>> name > >>>>> the > >>>>>>>>>>>>>>>>>>> predicate > >>>>>>>>>>>>>>>>>>>>>>>>>>> default Described described() { > >>>>>>>>>>>>>>>>>>>>>>>>>>> return new Described(null); > >>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> ---------- > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> where user's code becomes: > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> stream.filter(named("key", (k, v) -> true)); > >>> // > >>>>> note > >>>>>>>>>>>>>>> `named` > >>>>>>>>>>>>>>>>>>>> now > >>>>>>>>>>>>>>>>>>>>>>> just > >>>>>>>>>>>>>>>>>>>>>>>>>>> sets a Described("key") in "described()". > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> stream.filter(described(Described.as("key", /* > >>> any > >>>>>>>>>>>>>> other > >>>>>>>>>>>>>>> fancy > >>>>>>>>>>>>>>>>>>>>>>>>>> parameters > >>>>>>>>>>>>>>>>>>>>>>>>>>> in the future*/), (k, v) -> true)); > >>>>>>>>>>>>>>>>>>>>>>>>>>> ---------- > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> I feel it is not much likely that we'd need to > >>>>> extend > >>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>> further > >>>>>>>>>>>>>>>>>>>>> in > >>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>> future, so just a `String` would be good > >> enough. > >>>> But > >>>>>>>>>>>>>> just > >>>>>>>>>>>>>>>>>>>> listing > >>>>>>>>>>>>>>>>>>>>>>> all > >>>>>>>>>>>>>>>>>>>>>>>>>>> possibilities here. > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> Guozhang > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> On Fri, Jul 6, 2018 at 8:19 AM, John Roesler < > >>>>>>>>>>>>>>>>>>> j...@confluent.io > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Sorry I'm late to the party, but I missed the > >>>>> message > >>>>>>>>>>>>>>>>>>>> originally. > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Regarding the names, it's probably a good > >> idea > >>> to > >>>>>>>>>>>>>> stick to > >>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>> same > >>>>>>>>>>>>>>>>>>>>>>>>>>>> character set we're currently using: letters, > >>>>>>>>>>>>>> numbers, and > >>>>>>>>>>>>>>>>>>>>> hyphens. > >>>>>>>>>>>>>>>>>>>>>>>> The > >>>>>>>>>>>>>>>>>>>>>>>>>>>> names are used in Kafka topics, files and > >>>> folders, > >>>>>>> and > >>>>>>>>>>>>>>>>>>> RocksDB > >>>>>>>>>>>>>>>>>>>>>>>>>> databases, > >>>>>>>>>>>>>>>>>>>>>>>>>>>> and we also need them to work with the file > >>>> systems > >>>>>>> of > >>>>>>>>>>>>>>>>>>> Windows, > >>>>>>>>>>>>>>>>>>>>>>> Linux, > >>>>>>>>>>>>>>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>>>>>>>>> MacOS. My opinion is that with a situation > >> like > >>>>> that, > >>>>>>>>>>>>>> it's > >>>>>>>>>>>>>>>>>>>> better > >>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>>>> conservative. It might also be a good idea to > >>>>> impose > >>>>>>>>>>>>>> an > >>>>>>>>>>>>>>> upper > >>>>>>>>>>>>>>>>>>>>>>> limit on > >>>>>>>>>>>>>>>>>>>>>>>>>>> name > >>>>>>>>>>>>>>>>>>>>>>>>>>>> length to avoid running afoul of any of those > >>>>>>> systems. > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> --- > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> It seems like there's a small debate between > >> 1) > >>>>>>>>>>>>>> adding a > >>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>>>>>>> method to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> KStream (and maybe KTable) to modify its name > >>>> after > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>> fact, > >>>>>>>>>>>>>>>>>>>> or > >>>>>>>>>>>>>>>>>>>>> 2) > >>>>>>>>>>>>>>>>>>>>>>>>>>>> piggy-backing on the config objects where > >> they > >>>>> exist > >>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>> adding > >>>>>>>>>>>>>>>>>>>>> one > >>>>>>>>>>>>>>>>>>>>>>>>>> where > >>>>>>>>>>>>>>>>>>>>>>>>>>>> they don't. To me, #2 is the better > >> alternative > >>>>> even > >>>>>>>>>>>>>> though > >>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>> produces > >>>>>>>>>>>>>>>>>>>>>>>>>>>> more overloads and may be a bit awkward in > >>>> places. > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> The reason is simply that #1 is a high-level > >>>>>>>>>>>>>> departure from > >>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>> graph-building paradigm we're using in the > >> DSL. > >>>>>>>>>>>>>> Consider: > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Graph.node1(config).node2(config) > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> vs > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Graph.node1().config().node2().config() > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> We could have done either, but we picked the > >>>>> former. > >>>>>>> I > >>>>>>>>>>>>>>> think > >>>>>>>>>>>>>>>>>>>> it's > >>>>>>>>>>>>>>>>>>>>>>>>>>> probably > >>>>>>>>>>>>>>>>>>>>>>>>>>>> a good goal to try and stick to it so that > >>>>> developers > >>>>>>>>>>>>>> can > >>>>>>>>>>>>>>>>>>>> develop > >>>>>>>>>>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>>>>>>>> rely > >>>>>>>>>>>>>>>>>>>>>>>>>>>> on their instincts for how the DSL will > >> behave. > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> I do want to present one alternative to > >> adding > >>>> new > >>>>>>>>>>>>>> config > >>>>>>>>>>>>>>>>>>>>> objects: > >>>>>>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>>>>>>> can > >>>>>>>>>>>>>>>>>>>>>>>>>>>> just add a "name()" method to all our > >> "action" > >>>>>>>>>>>>>> interfaces. > >>>>>>>>>>>>>>>>>>> For > >>>>>>>>>>>>>>>>>>>>>>>> example, > >>>>>>>>>>>>>>>>>>>>>>>>>>>> I'll demonstrate how we can add a "name" to > >>>>> Predicate > >>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>> then > >>>>>>>>>>>>>>>>>>>>> use > >>>>>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> name a "KStream#filter" DSL operator: > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> public interface Predicate<K, V> { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> // existing method > >>>>>>>>>>>>>>>>>>>>>>>>>>>> boolean test(final K key, final V value); > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> // new default method adds the ability to > >>>> name > >>>>>>> the > >>>>>>>>>>>>>>>>>>>> predicate > >>>>>>>>>>>>>>>>>>>>>>>>>>>> default String name() { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> return null; > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> // new static factory method adds the > >>> ability > >>>>> to > >>>>>>>>>>>>>> wrap > >>>>>>>>>>>>>>>>>>>> lambda > >>>>>>>>>>>>>>>>>>>>>>>>>>> predicates > >>>>>>>>>>>>>>>>>>>>>>>>>>>> with a named predicate > >>>>>>>>>>>>>>>>>>>>>>>>>>>> static <K, V> Predicate<K, V> named(final > >>>>> String > >>>>>>>>>>>>>> name, > >>>>>>>>>>>>>>>>>>>> final > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Predicate<K, V> predicate) { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> return new Predicate<K, V>() { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> @Override > >>>>>>>>>>>>>>>>>>>>>>>>>>>> public boolean test(final K key, > >>>> final > >>>>> V > >>>>>>>>>>>>>>> value) { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> return predicate.test(key, > >>>> value); > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> @Override > >>>>>>>>>>>>>>>>>>>>>>>>>>>> public String name() { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> return name; > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> }; > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Then, here's how it would look to use it: > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> // Anonymous predicates continue to work just > >>>> fine > >>>>>>>>>>>>>>>>>>>>>>>>>>>> stream.filter((k, v) -> true); > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> // Devs can swap in a Predicate that > >> implements > >>>> the > >>>>>>>>>>>>>> name() > >>>>>>>>>>>>>>>>>>>>> method. > >>>>>>>>>>>>>>>>>>>>>>>>>>>> stream.filter(new Predicate<Object, > >> Object>() { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> @Override > >>>>>>>>>>>>>>>>>>>>>>>>>>>> public boolean test(final Object key, > >> final > >>>>>>> Object > >>>>>>>>>>>>>>>>>>> value) { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> return true; > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> @Override > >>>>>>>>>>>>>>>>>>>>>>>>>>>> public String name() { > >>>>>>>>>>>>>>>>>>>>>>>>>>>> return "hey"; > >>>>>>>>>>>>>>>>>>>>>>>>>>>> } > >>>>>>>>>>>>>>>>>>>>>>>>>>>> }); > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> // Or they can wrap their existing lambda > >> using > >>>> the > >>>>>>>>>>>>>> static > >>>>>>>>>>>>>>>>>>>>> factory > >>>>>>>>>>>>>>>>>>>>>>>>>> method > >>>>>>>>>>>>>>>>>>>>>>>>>>>> stream.filter(named("key", (k, v) -> true)); > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Just a thought. > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Overall, I think it's really valuable to be > >>> able > >>>> to > >>>>>>>>>>>>>> name > >>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>> processors, > >>>>>>>>>>>>>>>>>>>>>>>>>>>> for all the reasons you mentioned in the KIP. > >>> So > >>>>>>>>>>>>>> thank you > >>>>>>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>>>>>>>>>>>>> introducing > >>>>>>>>>>>>>>>>>>>>>>>>>>>> this! > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Thanks, > >>>>>>>>>>>>>>>>>>>>>>>>>>>> -John > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> On Thu, Jul 5, 2018 at 4:53 PM Florian > >>>> Hussonnois < > >>>>>>>>>>>>>>>>>>>>>>>>>> fhussonn...@gmail.com > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi, thank you very much for all you > >>> suggestions. > >>>>>>> I've > >>>>>>>>>>>>>>>>>>> started > >>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>> update > >>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> KIP ( > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>> https://cwiki.apache.org/confluence/display/KAFKA/KIP- > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> > >>>>>>> 307%3A+Allow+to+define+custom+processor+names+with+KStreams+DSL > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> ). > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Also, I propose to rename the Processed > >> class > >>>> into > >>>>>>>>>>>>>>>>>>> Described - > >>>>>>>>>>>>>>>>>>>>>>> this > >>>>>>>>>>>>>>>>>>>>>>>>>>> will > >>>>>>>>>>>>>>>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> more meaningful (but this is just a detail). > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> I'm OK to not enforcing uppercase for > >> specific > >>>>> names > >>>>>>>>>>>>>> but > >>>>>>>>>>>>>>>>>>>> should > >>>>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>>>>>>>> allow > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> arbitrary names with whitespaces for > >> example ? > >>>>>>>>>>>>>> Currently, > >>>>>>>>>>>>>>> I > >>>>>>>>>>>>>>>>>>>>> can't > >>>>>>>>>>>>>>>>>>>>>>>>>> tell > >>>>>>>>>>>>>>>>>>>>>>>>>>> if > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> this can lead to some side effects ? > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Le lun. 11 juin 2018 à 01:31, Matthias J. > >> Sax > >>> < > >>>>>>>>>>>>>>>>>>>>>>> matth...@confluent.io > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> écrit : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Just catching up on this thread. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I like the general idea. Couple of > >> comments: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - I think that adding `Processed` (or > >> maybe > >>> a > >>>>>>>>>>>>>> different > >>>>>>>>>>>>>>>>>>>> name?) > >>>>>>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> valid proposal for stateless operators that > >>>> only > >>>>>>>>>>>>>> have a > >>>>>>>>>>>>>>>>>>>> single > >>>>>>>>>>>>>>>>>>>>>>>>>>> overload > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> atm. It would align with the overall API > >>>> design. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - for all methods with multiple existing > >>>>>>>>>>>>>> overloads, we > >>>>>>>>>>>>>>> can > >>>>>>>>>>>>>>>>>>>>>>>>>> consider > >>>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> extend `Consumed`, `Produced`, > >> `Materialized` > >>>> etc > >>>>>>>>>>>>>> to take > >>>>>>>>>>>>>>>>>>> an > >>>>>>>>>>>>>>>>>>>>>>>>>>> additional > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor name (not sure atm how elegant > >> this > >>>> is; > >>>>>>> we > >>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>>>>>> need > >>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "play" with the API a little bit; the > >>> advantage > >>>>>>>>>>>>>> would be, > >>>>>>>>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>>>>>>> do > >>>>>>>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> add more overloads what seems to be key for > >>>> this > >>>>>>>>>>>>>> KIP) > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - operators return void: while I agree > >> that > >>>> the > >>>>>>>>>>>>>> "name > >>>>>>>>>>>>>>>>>>> first" > >>>>>>>>>>>>>>>>>>>>>>>>>>> chaining > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> idea is not very intuitive, it might still > >>>> work, > >>>>> if > >>>>>>>>>>>>>> we > >>>>>>>>>>>>>>> name > >>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>> method > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> correctly (again, we would need to "play" > >>> with > >>>>> the > >>>>>>>>>>>>>> API a > >>>>>>>>>>>>>>>>>>>> little > >>>>>>>>>>>>>>>>>>>>>>> bit > >>>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> see) > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - for DSL operators that are translated to > >>>>>>> multiple > >>>>>>>>>>>>>>> nodes: > >>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>> might > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> make sense to use the specified operator > >> name > >>>> as > >>>>>>>>>>>>>> prefix > >>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>> add > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> reasonable suffixes. For example, a join > >>>>> translates > >>>>>>>>>>>>>> into > >>>>>>>>>>>>>>> 5 > >>>>>>>>>>>>>>>>>>>>>>>>>> operators > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> that could be name > >>> "name-left-store-processor", > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "name-left-join-processor", > >>>>>>>>>>>>>> "name-right-store-processor", > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "name-right-join-processor", and > >>>>>>>>>>>>>>>>>>> "name-join-merge-processor" > >>>>>>>>>>>>>>>>>>>>> (or > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> similar). Maybe just using numbers might > >> also > >>>>> work. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - I think, we should strip the number > >>> suffixes > >>>>> if > >>>>>>>>>>>>>> a user > >>>>>>>>>>>>>>>>>>>>>>> provides > >>>>>>>>>>>>>>>>>>>>>>>>>>>> names > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - enforcing upper case seems to be tricky: > >>> for > >>>>>>>>>>>>>> example, > >>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>> do > >>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> enforce upper case for store names and we > >>>> cannot > >>>>>>>>>>>>>> easily > >>>>>>>>>>>>>>>>>>>> change > >>>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>> as > >>>>>>>>>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> would break compatibility -- thus, for > >>>>> consistency > >>>>>>>>>>>>>>> reasons > >>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>>>> might > >>>>>>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> want to do this > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - for better understand of the impact of > >> the > >>>>> KIP, > >>>>>>>>>>>>>> it > >>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>> quite > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> helpful if you would list all method names > >>> that > >>>>> are > >>>>>>>>>>>>>>>>>>> affected > >>>>>>>>>>>>>>>>>>>> in > >>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>> KIP > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (ie, list all newly added overloads) > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -Matthias > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> On 5/31/18 6:40 PM, Guozhang Wang wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Re 1: I think changing the KStreamImpl / > >>>>>>>>>>>>>> KTableImpl to > >>>>>>>>>>>>>>>>>>> allow > >>>>>>>>>>>>>>>>>>>>>>>>>>>> modifying > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor name after the operator is fine > >> as > >>>>> long > >>>>>>>>>>>>>> as we > >>>>>>>>>>>>>>> do > >>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>> check > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> again > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> when modifying that. In fact, we are > >> having > >>>> some > >>>>>>>>>>>>>>> topology > >>>>>>>>>>>>>>>>>>>>>>>>>>>> optimization > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> going on which may modify processor names > >> in > >>>> the > >>>>>>>>>>>>>> final > >>>>>>>>>>>>>>>>>>>>> topology > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> anyways ( > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> https://github.com/apache/kafka/pull/4983 > >> ). > >>>>>>>>>>>>>>> Semantically > >>>>>>>>>>>>>>>>>>> I > >>>>>>>>>>>>>>>>>>>>>>> think > >>>>>>>>>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> easier to understand to developers than > >>>>> "deciding > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>>>>>>>>>> name > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the next operator". > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Re 2: Yeah I'm thinking that for operators > >>>> that > >>>>>>>>>>>>>>> translates > >>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> multiple > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor names, we can still use the > >>> provided > >>>>>>>>>>>>>> "hint" to > >>>>>>>>>>>>>>>>>>>> name > >>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> names, e.g. for Joins we can name them as > >>>>>>>>>>>>>>> `join-foo-this` > >>>>>>>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> `join-foo-that` etc if user calls > >>> `as("foo")`. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Re 3: The motivation I had about removing > >>> the > >>>>>>>>>>>>>> suffix is > >>>>>>>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>>>>>> it > >>>>>>>>>>>>>>>>>>>>>>>>>> has > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> huge > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> restrictions on topology compatibilities: > >>>>> consider > >>>>>>>>>>>>>> if > >>>>>>>>>>>>>>> user > >>>>>>>>>>>>>>>>>>>>> code > >>>>>>>>>>>>>>>>>>>>>>>>>>>> added a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> operator, or library does some > >> optimization > >>> to > >>>>>>>>>>>>>> remove > >>>>>>>>>>>>>>> some > >>>>>>>>>>>>>>>>>>>>>>>>>>> operators, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> suffix indexing may be changed for a large > >>>>> amount > >>>>>>>>>>>>>> of the > >>>>>>>>>>>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> names: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> this will in turn change the internal > >> state > >>>>> store > >>>>>>>>>>>>>> names, > >>>>>>>>>>>>>>>>>>> as > >>>>>>>>>>>>>>>>>>>>> well > >>>>>>>>>>>>>>>>>>>>>>>>>> as > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> internal topic names as well, making the > >> new > >>>>>>>>>>>>>> application > >>>>>>>>>>>>>>>>>>>>>>> topology > >>>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> incompatible with the ones. One rationale > >> I > >>>> had > >>>>>>>>>>>>>> about > >>>>>>>>>>>>>>> this > >>>>>>>>>>>>>>>>>>>> KIP > >>>>>>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> aligned this effort, moving forward we can > >>>> allow > >>>>>>>>>>>>>> users > >>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>> customize > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> internal names so that they can still be > >>>> reused > >>>>>>>>>>>>>> even > >>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>>>>>>> topology > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> changes > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (e.g. KIP-230), so I think removing the > >>> suffix > >>>>>>>>>>>>>> index > >>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>> more > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> applicable in the long run. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Guozhang > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> On Thu, May 31, 2018 at 3:08 PM, Florian > >>>>>>>>>>>>>> Hussonnois < > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> fhussonn...@gmail.com> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi , > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thank you very much for your feedback. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1/ > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I agree that overloading most of the > >>> methods > >>>>> with > >>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>> Processed > >>>>>>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ideal. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I've started modifying the KStream API > >> and > >>> I > >>>>> got > >>>>>>>>>>>>>> to the > >>>>>>>>>>>>>>>>>>>> same > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> conclusion. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Also ading a new method directly to > >>>> KStreamImpl > >>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>> KTableImpl > >>>>>>>>>>>>>>>>>>>>>>>>>>>> classes > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> seems to be a better option. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> However a processor name cannot be > >>> redefined > >>>>>>> after > >>>>>>>>>>>>>>>>>>> calling > >>>>>>>>>>>>>>>>>>>> an > >>>>>>>>>>>>>>>>>>>>>>>>>>>> operator > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (or > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> maybe I miss something in the code). > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> From my understanding, this will only set > >>> the > >>>>>>>>>>>>>> KStream > >>>>>>>>>>>>>>>>>>> name > >>>>>>>>>>>>>>>>>>>>>>>>>>> property > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor name previsouly added to the > >>>> topology > >>>>>>>>>>>>>>> builder - > >>>>>>>>>>>>>>>>>>>>>>>>>> leading > >>>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> InvalidTopology exception. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> So the new method should actually defines > >>> the > >>>>>>>>>>>>>> name of > >>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>> next > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Below is an example : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> *stream.as <http://stream.as > >>>>>>>>>>>>>>>>>>>>>>>>>>>> (Processed.name("MAPPE_TO_UPPERCASE")* > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * .map( (k, v) -> > >> KeyValue.pair(k, > >>>>>>>>>>>>>>>>>>>>> v.toUpperCase()))* > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I think this approach could solve the > >> cases > >>>> for > >>>>>>>>>>>>>> methods > >>>>>>>>>>>>>>>>>>>>>>>>>> returning > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> void ? > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Regarding this new method we have two > >>>> possible > >>>>>>>>>>>>>>>>>>>>> implementations > >>>>>>>>>>>>>>>>>>>>>>> : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. Adding a method like : > >>> withName(String > >>>>>>>>>>>>>>>>>>> processorName) > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. or adding a method accepting an > >>>> Processed > >>>>>>>>>>>>>> object > >>>>>>>>>>>>>>> : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> as(Processed). > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I think solution 2. is preferable as the > >>>>>>> Processed > >>>>>>>>>>>>>>> class > >>>>>>>>>>>>>>>>>>>>> could > >>>>>>>>>>>>>>>>>>>>>>>>>> be > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> enriched > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> further (in futur). > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2/ > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> As Guozhang said some operators add > >>> internal > >>>>>>>>>>>>>>> processors. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> For example the branch() method create > >> one > >>>>>>>>>>>>>>> KStreamBranch > >>>>>>>>>>>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> route > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> records and one KStreamPassThrough > >>> processor > >>>>> for > >>>>>>>>>>>>>> each > >>>>>>>>>>>>>>>>>>>> branch. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> In that situation only the parent > >> processor > >>>> can > >>>>>>> be > >>>>>>>>>>>>>>> named. > >>>>>>>>>>>>>>>>>>>> For > >>>>>>>>>>>>>>>>>>>>>>>>>>>> children > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processors we could keep the current > >>>> behaviour > >>>>>>>>>>>>>> that > >>>>>>>>>>>>>>> add a > >>>>>>>>>>>>>>>>>>>>>>> suffix > >>>>>>>>>>>>>>>>>>>>>>>>>>>> (i.e > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> KSTREAM-BRANCHCHILD-) > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> This also the case for the join() method > >>> that > >>>>>>>>>>>>>> result to > >>>>>>>>>>>>>>>>>>>>> adding > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> multiple > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processors to the topology (windowing, > >>>>> left/right > >>>>>>>>>>>>>> joins > >>>>>>>>>>>>>>>>>>>> and a > >>>>>>>>>>>>>>>>>>>>>>>>>>> merge > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor). > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I think, like for the branch method users > >>>> could > >>>>>>>>>>>>>> only > >>>>>>>>>>>>>>>>>>>> define a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> name prefix. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3/ > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I think we should still added a suffix > >>> like > >>>>>>>>>>>>>>>>>>> "-0000000000" > >>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> name and enforce uppercases as this will > >>> keep > >>>>>>> some > >>>>>>>>>>>>>>>>>>>>> consistency > >>>>>>>>>>>>>>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ones generated by the API. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 4/ > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Yes, the KTable interface should be > >>> modified > >>>>> like > >>>>>>>>>>>>>>> KStream > >>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>> allow > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> custom > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor names definition. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thanks, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Le jeu. 31 mai 2018 à 19:18, Damian Guy < > >>>>>>>>>>>>>>>>>>>>> damian....@gmail.com> > >>>>>>>>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> écrit > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thanks for the KIP. What about KTable > >> and > >>>>> other > >>>>>>>>>>>>>> DSL > >>>>>>>>>>>>>>>>>>>>>>> interfaces? > >>>>>>>>>>>>>>>>>>>>>>>>>>>> Will > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> they > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> not want to be able to do the same > >> thing? > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> It would be good to see a complete set > >> of > >>>> the > >>>>>>>>>>>>>> public > >>>>>>>>>>>>>>> API > >>>>>>>>>>>>>>>>>>>>>>>>>> changes. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Cheers, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Damian > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> On Wed, 30 May 2018 at 19:45 Guozhang > >>> Wang < > >>>>>>>>>>>>>>>>>>>>>>> wangg...@gmail.com > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hello Florian, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thanks for the KIP. I have some meta > >>>>> feedbacks > >>>>>>>>>>>>>> on the > >>>>>>>>>>>>>>>>>>>>>>>>>> proposal: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 1. You mentioned that this `Processed` > >>>> object > >>>>>>>>>>>>>> will be > >>>>>>>>>>>>>>>>>>>> added > >>>>>>>>>>>>>>>>>>>>>>>>>> to a > >>>>>>>>>>>>>>>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> overloaded variant of all the stateless > >>>>>>>>>>>>>> operators, > >>>>>>>>>>>>>>> what > >>>>>>>>>>>>>>>>>>>>> about > >>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> stateful > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> operators? Would like to hear your > >>> opinions > >>>>> if > >>>>>>>>>>>>>> you > >>>>>>>>>>>>>>> have > >>>>>>>>>>>>>>>>>>>>>>>>>> thought > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> about > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> that: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> note for stateful operators they will > >>>> usually > >>>>>>> be > >>>>>>>>>>>>>>> mapped > >>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> multiple > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor node names, so we probably > >> need > >>>> to > >>>>>>>>>>>>>> come up > >>>>>>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>>>> some > >>>>>>>>>>>>>>>>>>>>>>>>>>>> ways > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> define all their names. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 2. I share the same concern with Bill > >> as > >>>> for > >>>>>>>>>>>>>> adding > >>>>>>>>>>>>>>>>>>> lots > >>>>>>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> overload > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> functions into the stateless operators, > >>> as > >>>> we > >>>>>>>>>>>>>> have > >>>>>>>>>>>>>>> just > >>>>>>>>>>>>>>>>>>>>> spent > >>>>>>>>>>>>>>>>>>>>>>>>>>>> quite > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> some > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> effort in trimming them since 1.0.0 > >>>> release. > >>>>> If > >>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>> goal > >>>>>>>>>>>>>>>>>>>> is > >>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> just > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> provide > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> some "hints" on the generated processor > >>>> node > >>>>>>>>>>>>>> names, > >>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>> strictly > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> enforcing > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the exact names that to be generated, > >>> then > >>>>> how > >>>>>>>>>>>>>> about > >>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>> just > >>>>>>>>>>>>>>>>>>>>>>>>>>> add a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> new > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> function to `KStream` and `KTable` > >>> classes > >>>>>>> like: > >>>>>>>>>>>>>>>>>>>>>>>>>>> "as(Processed)", > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> semantics as "the latest operators that > >>>>>>>>>>>>>> generate this > >>>>>>>>>>>>>>>>>>>>> KStream > >>>>>>>>>>>>>>>>>>>>>>>>>> / > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> KTable > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> will > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> be named accordingly to this hint". > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> The only caveat, is that for all > >>> operators > >>>>> like > >>>>>>>>>>>>>>>>>>>>> `KStream#to` > >>>>>>>>>>>>>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> `KStream#print` that returns void, this > >>>>>>>>>>>>>> alternative > >>>>>>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>> work. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> But > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> for > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the current operators: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> a. KStream#print, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> b. KStream#foreach, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> c. KStream#to, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> d. KStream#process > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I personally felt that except > >>>>> `KStream#process` > >>>>>>>>>>>>>> users > >>>>>>>>>>>>>>>>>>>> would > >>>>>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> usually > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> bother to override their names, and for > >>>>>>>>>>>>>>>>>>> `KStream#process` > >>>>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>>>>>>>> could > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> add > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> an > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> overload variant with the additional > >>>>> Processed > >>>>>>>>>>>>>>> object. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 3. In your example, the processor names > >>> are > >>>>>>>>>>>>>> still > >>>>>>>>>>>>>>> added > >>>>>>>>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> suffix > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> like > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> " > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -0000000000", is this intentional? If > >>> yes, > >>>>> why > >>>>>>>>>>>>>> (I > >>>>>>>>>>>>>>>>>>> thought > >>>>>>>>>>>>>>>>>>>>>>> with > >>>>>>>>>>>>>>>>>>>>>>>>>>>> user > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> specified processor name hints we will > >>> not > >>>>> add > >>>>>>>>>>>>>> suffix > >>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> distinguish > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> different nodes of the same type any > >>> more)? > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Guozhang > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> On Tue, May 29, 2018 at 6:47 AM, Bill > >>>> Bejeck > >>>>> < > >>>>>>>>>>>>>>>>>>>>>>>>>> bbej...@gmail.com > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi Florian, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thanks for the KIP. I think being > >> able > >>> to > >>>>> add > >>>>>>>>>>>>>> more > >>>>>>>>>>>>>>>>>>>>> context > >>>>>>>>>>>>>>>>>>>>>>>>>> to > >>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> processor names would be useful. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I like the idea of adding a > >>>>>>>>>>>>>> "withProcessorName" to > >>>>>>>>>>>>>>>>>>>>> Produced, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Consumed > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> and > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Joined. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> But instead of adding the "Processed" > >>>>>>>>>>>>>> parameter to a > >>>>>>>>>>>>>>>>>>>> large > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> percentage > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> the methods, which would result in > >>>>> overloaded > >>>>>>>>>>>>>>> methods > >>>>>>>>>>>>>>>>>>>>> (which > >>>>>>>>>>>>>>>>>>>>>>>>>> we > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> removed > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> quite a bit with KIP-182) what do you > >>>> think > >>>>> of > >>>>>>>>>>>>>>> adding > >>>>>>>>>>>>>>>>>>> a > >>>>>>>>>>>>>>>>>>>>>>>>>> method > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> to the AbstractStream class > >>>> "withName(String > >>>>>>>>>>>>>>>>>>>>>>> processorName)"? > >>>>>>>>>>>>>>>>>>>>>>>>>>> BTW > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> I"m > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> not > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> married to the method name, it's the > >>> best > >>>> I > >>>>>>>>>>>>>> can do > >>>>>>>>>>>>>>> off > >>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>> top > >>>>>>>>>>>>>>>>>>>>>>>>>>> of > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> my > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> head. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> For the methods that return void, we'd > >>>> have > >>>>> to > >>>>>>>>>>>>>> add a > >>>>>>>>>>>>>>>>>>>>>>>>>> parameter, > >>>>>>>>>>>>>>>>>>>>>>>>>>>> but > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> that > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> would at least cut down on the number > >> of > >>>>>>>>>>>>>> overloaded > >>>>>>>>>>>>>>>>>>>>> methods > >>>>>>>>>>>>>>>>>>>>>>>>>> in > >>>>>>>>>>>>>>>>>>>>>>>>>>>> the > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> API. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Just my 2 cents. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Thanks, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Bill > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> On Sun, May 27, 2018 at 4:13 PM, > >> Florian > >>>>>>>>>>>>>> Hussonnois > >>>>>>>>>>>>>>> < > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> fhussonn...@gmail.com > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> wrote: > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Hi, > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> I would like to start a new > >> discussion > >>> on > >>>>>>>>>>>>>> following > >>>>>>>>>>>>>>>>>>>> KIP : > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> > >> https://cwiki.apache.org/confluence/display/KAFKA/KIP- > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> > >>>>>>> 307%3A+Allow+to+define+custom+processor+names+with+KStreams+DSL > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> This is still a draft. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Looking forward for your feedback. > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Florian HUSSONNOIS > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Florian HUSSONNOIS > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> Florian HUSSONNOIS > >>>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>>>>> Florian HUSSONNOIS > >>>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>>> Florian HUSSONNOIS > >>>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>>> -- > >>>>>>>>>>>>>>> Florian HUSSONNOIS > >>>>>>>>>>>>>>> > >>>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>> > >>>>>>>>>>>>> -- > >>>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>>> > >>>>>>>>>>>> > >>>>>>>>>>>> > >>>>>>>>>>>> -- > >>>>>>>>>>>> -- Guozhang > >>>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> > >>>>>>>>>>> -- > >>>>>>>>>>> -- Guozhang > >>>>>>>>>>> > >>>>>>>>>> > >>>>>>>>>> > >>>>>>>>> > >>>>>>>>> > >>>>>>>> > >>>>>>> > >>>>>>> > >>>>>> > >>>>> > >>>>> > >>>> > >>> > >> > >> > >> -- > >> Florian HUSSONNOIS > >> > > > > > >