public IKTable <Windowed <K>, VR> Aggregate <VR>(Initializer <VR> initializer, Aggregator <K, V, VR> aggregator, Materialized <K, VR, WindowStore <Bytes, byte[]> > materialized, string named = null)
        {
            CheckIfParamNull(initializer, "initializer");
            CheckIfParamNull(aggregator, "aggregator");

            materialized = materialized ?? Materialized <K, VR, WindowStore <Bytes, byte[]> > .Create();

            if (materialized.KeySerdes == null)
            {
                materialized.WithKeySerdes(KeySerdes);
            }

            string name = new Named(named).OrElseGenerateWithPrefix(builder, KGroupedStream.AGGREGATE_NAME);

            materialized.UseProvider(builder, KGroupedStream.AGGREGATE_NAME);

            var aggSupplier = new KStreamWindowAggregate <K, V, VR, W>(
                windowOptions,
                materialized.StoreName,
                initializer,
                aggregator);

            ISerDes <Windowed <K> > windowSerdes = materialized.KeySerdes != null ? new TimeWindowedSerDes <K>(materialized.KeySerdes, windowOptions.Size) : null;

            return(aggBuilder.BuildWindow(name,
                                          new TimestampedWindowStoreMaterializer <K, VR, W>(windowOptions, materialized).Materialize(),
                                          aggSupplier,
                                          materialized.QueryableStoreName,
                                          windowSerdes,
                                          materialized.ValueSerdes));
        }
Exemple #2
0
        /// <summary>
        /// Create a <see cref="IGlobalKTable{K,V}"/> for the specified topic.
        /// Input keyvalue records with <code>null</code> key will be dropped.
        /// The resulting <see cref="IGlobalKTable{K,V}"/> will be materialized in a local <see cref="IKeyValueStore{K, V}"/> using the given
        /// <see cref="Materialized{K, V, S}"/> instance.
        /// However, no internal changelog topic is created since the original input topic can be used for recovery.
        /// Note that <see cref="IGlobalKTable{K,V}"/> always applies <code>"auto.offset.reset"</code> strategy <code>"earliest"</code>
        /// regardless of the specified value in <see cref="IStreamConfig"/>.
        /// </summary>
        /// <typeparam name="K">Key type of record</typeparam>
        /// <typeparam name="V">Value type of record</typeparam>
        /// <param name="topic">the topic name, can't be null</param>
        /// <param name="keySerdes">Key deserializer</param>
        /// <param name="valueSerdes">Value deserializer</param>
        /// <param name="materialized">the instance of <see cref="Materialized{K, V, S}"/> used to materialize a state store.</param>
        /// <param name="named">Processor name</param>
        /// <param name="extractor">the timestamp extractor to be used. If null the default timestamp extractor from config will be used</param>
        /// <returns>a <see cref="IGlobalKTable{K,V}"/> for the specified topic</returns>
        /// <exception cref="ArgumentException">Throw <see cref="ArgumentException"/> if topic is null or empty</exception>
        public IGlobalKTable <K, V> GlobalTable <K, V>(string topic, ISerDes <K> keySerdes, ISerDes <V> valueSerdes, Materialized <K, V, IKeyValueStore <Bytes, byte[]> > materialized, string named, ITimestampExtractor extractor)
        {
            materialized = materialized ?? Materialized <K, V, IKeyValueStore <Bytes, byte[]> > .Create();

            var consumedInternal = new ConsumedInternal <K, V>(named, keySerdes, valueSerdes, extractor);

            materialized.UseProvider(internalStreamBuilder, $"{topic}-")?.InitConsumed(consumedInternal);

            return(internalStreamBuilder.GlobalTable(topic, consumedInternal, materialized));
        }
Exemple #3
0
        /// <summary>
        /// Create a <see cref="IKTable{K, V}"/> for the specified topic.
        /// Input keyvalue records with null key will be dropped.
        ///
        /// Note that the specified input topic must be partitioned by key.
        /// If this is not the case the returned <see cref="IKTable{K, V}"/> will be corrupted.
        ///
        /// The resulting <see cref="IKTable{K, V}"/> will be materialized in a local <see cref="IKeyValueStore{K, V}"/> using the given
        /// <see cref="Materialized{K, V, S}"/> instance.
        /// </summary>
        /// <typeparam name="K">Key type of record</typeparam>
        /// <typeparam name="V">Value type of record</typeparam>
        /// <param name="topic">the topic name, can't be null</param>
        /// <param name="keySerdes">Key deserializer</param>
        /// <param name="valueSerdes">Value deserializer</param>
        /// <param name="materialized">the instance of <see cref="Materialized{K, V, S}"/> used to materialize a state store.</param>
        /// <param name="named">Processor name</param>
        /// <param name="extractor">the timestamp extractor to be used. If null the default timestamp extractor from config will be used</param>
        /// <returns>a <see cref="IKTable{K, V}"/> for the specified topic</returns>
        /// <exception cref="ArgumentException">Throw <see cref="ArgumentException"/> if topic is null or empty</exception>
        public IKTable <K, V> Table <K, V>(string topic, ISerDes <K> keySerdes, ISerDes <V> valueSerdes, Materialized <K, V, IKeyValueStore <Bytes, byte[]> > materialized, string named, ITimestampExtractor extractor)
        {
            if (string.IsNullOrEmpty(topic))
            {
                throw new ArgumentException("Topic of KTable must not be null or empty");
            }

            materialized = materialized ?? Materialized <K, V, IKeyValueStore <Bytes, byte[]> > .Create();

            var consumedInternal = new ConsumedInternal <K, V>(named, keySerdes, valueSerdes, extractor);

            materialized.UseProvider(internalStreamBuilder, $"{topic}-").InitConsumed(consumedInternal);

            return(internalStreamBuilder.Table(topic, consumedInternal, materialized));
        }
        public IKTable <Windowed <K>, V> Reduce(Reducer <V> reducer, Materialized <K, V, WindowStore <Bytes, byte[]> > materialized, string named = null)
        {
            CheckIfParamNull(reducer, "reducer");

            materialized = materialized ?? Materialized <K, V, WindowStore <Bytes, byte[]> > .Create();

            if (materialized.KeySerdes == null)
            {
                materialized.WithKeySerdes(KeySerdes);
            }

            if (materialized.ValueSerdes == null)
            {
                materialized.WithValueSerdes(ValueSerdes);
            }

            string name = new Named(named).OrElseGenerateWithPrefix(builder, KGroupedStream.REDUCE_NAME);

            materialized.UseProvider(builder, KGroupedStream.REDUCE_NAME);

            var aggSupplier = new KStreamWindowAggregate <K, V, V, W>(
                windowOptions,
                materialized.StoreName,
                () => default,
Exemple #5
0
        public IKTable <K, VR> Join <K, V, V0, VR>(
            IKTable <K, V> tableLeft,
            IKTable <K, V0> tableRight,
            IValueJoiner <V, V0, VR> joiner,
            string named,
            Materialized <K, VR, IKeyValueStore <Bytes, byte[]> > materializedInternal)
        {
            var           renamed        = new Named(named);
            var           joinMergeName  = renamed.OrElseGenerateWithPrefix(builder, KTable.MERGE_NAME);
            ISet <string> allSourceNodes = new HashSet <string>((tableLeft as AbstractStream <K, V>).SetSourceNodes);

            allSourceNodes.AddRange((tableRight as AbstractStream <K, V0>).SetSourceNodes);
            materializedInternal.UseProvider(builder, $"{joinMergeName}-");

            if (leftOuter)
            {
                (tableLeft as IKTableGetter <K, V>)?.EnableSendingOldValues();
            }

            if (rightOuter)
            {
                (tableRight as IKTableGetter <K, V0>)?.EnableSendingOldValues();
            }

            AbstractKTableKTableJoin <K, VR, V, V0> joinLeft  = null;
            AbstractKTableKTableJoin <K, VR, V0, V> joinRight = null;

            if (!leftOuter) // INNER JOIN
            {
                joinLeft  = new KTableKTableInnerJoin <K, VR, V, V0>((tableLeft as IKTableGetter <K, V>), (tableRight as IKTableGetter <K, V0>), joiner);
                joinRight = new KTableKTableInnerJoin <K, VR, V0, V>((tableRight as IKTableGetter <K, V0>), (tableLeft as IKTableGetter <K, V>), joiner.Reverse());
            }
            else if (!rightOuter) // LEFT JOIN
            {
                joinLeft  = new KTableKTableLeftJoin <K, VR, V, V0>((tableLeft as IKTableGetter <K, V>), (tableRight as IKTableGetter <K, V0>), joiner);
                joinRight = new KTableKTableRightJoin <K, VR, V0, V>((tableRight as IKTableGetter <K, V0>), (tableLeft as IKTableGetter <K, V>), joiner.Reverse());
            }
            else // OUTER JOIN
            {
                joinLeft  = new KTableKTableOuterJoin <K, VR, V, V0>((tableLeft as IKTableGetter <K, V>), (tableRight as IKTableGetter <K, V0>), joiner);
                joinRight = new KTableKTableOuterJoin <K, VR, V0, V>((tableRight as IKTableGetter <K, V0>), (tableLeft as IKTableGetter <K, V>), joiner.Reverse());
            }

            var joinLeftName  = renamed.SuffixWithOrElseGet("-join-this", builder, KTable.JOINTHIS_NAME);
            var joinRigthName = renamed.SuffixWithOrElseGet("-join-other", builder, KTable.JOINOTHER_NAME);

            var joinLeftProcessorParameters  = new TableProcessorParameters <K, V>(joinLeft, joinLeftName);
            var joinRightProcessorParameters = new TableProcessorParameters <K, V0>(joinRight, joinRigthName);

            if (materializedInternal.KeySerdes == null && tableLeft is AbstractStream <K, V> )
            {
                materializedInternal.WithKeySerdes((tableLeft as AbstractStream <K, V>).KeySerdes);
            }

            ISerDes <K>  keySerdes          = materializedInternal.KeySerdes;
            ISerDes <VR> ValueSerdes        = materializedInternal.ValueSerdes;
            string       queryableStoreName = materializedInternal.QueryableStoreName;
            StoreBuilder <TimestampedKeyValueStore <K, VR> > storeBuilder = queryableStoreName != null ? new TimestampedKeyValueStoreMaterializer <K, VR>(materializedInternal).Materialize() : null;

            var tableNode = new KTableKTableJoinNode <K, V, V0, VR>(
                joinMergeName,
                joinLeftProcessorParameters,
                joinRightProcessorParameters,
                (tableLeft as AbstractStream <K, V>).NameNode,
                (tableRight as AbstractStream <K, V0>).NameNode,
                (tableLeft as IKTableGetter <K, V>).ValueGetterSupplier.StoreNames,
                (tableRight as IKTableGetter <K, V0>).ValueGetterSupplier.StoreNames,
                queryableStoreName,
                storeBuilder);

            builder.AddGraphNode((tableLeft as AbstractStream <K, V>).Node, tableNode);

            return(new KTable <K, VR, VR>(
                       tableNode.streamGraphNode,
                       keySerdes,
                       ValueSerdes,
                       allSourceNodes.ToList(),
                       queryableStoreName,
                       tableNode.JoinMergeProcessorSupplier,
                       tableNode,
                       builder));
        }
Exemple #6
0
        private IKTable <K, VR> DoMapValues <VR>(IValueMapperWithKey <K, V, VR> mapper, string named, Materialized <K, VR, IKeyValueStore <Bytes, byte[]> > materializedInternal)
        {
            if (mapper == null)
            {
                throw new ArgumentNullException($"MapValues() doesn't allow null mapper function");
            }

            ISerDes <K>  keySerde;
            ISerDes <VR> valueSerde;
            String       queryableStoreName;
            StoreBuilder <TimestampedKeyValueStore <K, VR> > storeBuilder;

            if (materializedInternal != null)
            {
                // we actually do not need to generate store names at all since if it is not specified, we will not
                // materialize the store; but we still need to burn one index BEFORE generating the processor to keep compatibility.
                if (materializedInternal.StoreName == null)
                {
                    builder.NewStoreName(MAPVALUES_NAME);
                }
                keySerde   = materializedInternal.KeySerdes != null ? materializedInternal.KeySerdes : this.keySerdes;
                valueSerde = materializedInternal.ValueSerdes != null ? materializedInternal.ValueSerdes : null;
                // ONLY FOR CALCULATE PROPERTY queriable
                materializedInternal.UseProvider(null, null);
                queryableStoreName = materializedInternal.QueryableStoreName;
                // only materialize if materialized is specified and it has queryable name
                storeBuilder = queryableStoreName != null ? new TimestampedKeyValueStoreMaterializer <K, VR>(materializedInternal).Materialize() : null;
            }
            else
            {
                keySerde           = this.keySerdes;
                valueSerde         = null;
                queryableStoreName = null;
                storeBuilder       = null;
            }

            var name = new Named(named).OrElseGenerateWithPrefix(this.builder, MAPVALUES_NAME);

            var processorSupplier   = new KTableMapValues <K, V, VR>(this, mapper, queryableStoreName);
            var processorParameters = new TableProcessorParameters <K, V>(processorSupplier, name);

            var tableNode = new TableProcessorNode <K, V, K, VR>(
                name,
                processorParameters,
                storeBuilder
                );

            builder.AddGraphNode(this.node, tableNode);

            // don't inherit parent value serde, since this operation may change the value type, more specifically:
            // we preserve the key following the order of 1) materialized, 2) parent, 3) null
            // we preserve the value following the order of 1) materialized, 2) null
            return(new KTable <K, V, VR>(
                       name,
                       keySerde,
                       valueSerde,
                       this.setSourceNodes,
                       queryableStoreName,
                       processorSupplier,
                       tableNode,
                       builder
                       ));
        }
Exemple #7
0
        private IKTable <K, V> DoFilter(Func <K, V, bool> predicate, string named, Materialized <K, V, IKeyValueStore <Bytes, byte[]> > materializedInternal, bool filterNot)
        {
            ISerDes <K> keySerde;
            ISerDes <V> valueSerde;
            String      queryableStoreName;
            StoreBuilder <TimestampedKeyValueStore <K, V> > storeBuilder;

            if (predicate == null)
            {
                throw new ArgumentNullException($"Filter() doesn't allow null predicate function");
            }

            if (materializedInternal != null)
            {
                // we actually do not need to generate store names at all since if it is not specified, we will not
                // materialize the store; but we still need to burn one index BEFORE generating the processor to keep compatibility.
                if (materializedInternal.StoreName == null)
                {
                    builder.NewStoreName(FILTER_NAME);
                }
                // we can inherit parent key and value serde if user do not provide specific overrides, more specifically:
                // we preserve the key following the order of 1) materialized, 2) parent
                keySerde = materializedInternal.KeySerdes != null ? materializedInternal.KeySerdes : this.keySerdes;
                // we preserve the value following the order of 1) materialized, 2) parent
                valueSerde = materializedInternal.ValueSerdes != null ? materializedInternal.ValueSerdes : this.valueSerdes;
                // ONLY FOR CALCULATE PROPERTY queriable
                materializedInternal.UseProvider(null, null);
                queryableStoreName = materializedInternal.QueryableStoreName;
                // only materialize if materialized is specified and it has queryable name
                storeBuilder = queryableStoreName != null ? (new TimestampedKeyValueStoreMaterializer <K, V>(materializedInternal)).Materialize() : null;
            }
            else
            {
                keySerde           = this.keySerdes;
                valueSerde         = this.valueSerdes;
                queryableStoreName = null;
                storeBuilder       = null;
            }

            var name = new Named(named).OrElseGenerateWithPrefix(this.builder, FILTER_NAME);

            IProcessorSupplier <K, Change <V> > processorSupplier = new KTableFilter <K, V>(this, predicate, filterNot, queryableStoreName);

            var processorParameters = new TableProcessorParameters <K, V>(processorSupplier, name);

            var tableNode = new TableProcessorNode <K, V, K, V>(
                name,
                processorParameters,
                storeBuilder
                );

            builder.AddGraphNode(this.node, tableNode);

            return(new KTable <K, V, V>(name,
                                        keySerde,
                                        valueSerde,
                                        this.setSourceNodes,
                                        queryableStoreName,
                                        processorSupplier,
                                        tableNode,
                                        builder));
        }