Печать Kafka Stream Вход в консоль?

Я просматривал много документации Kafka для приложения Java, над которым я работаю. Я попытался войти в синтаксис лямбда, введенный в Java 8, но я немного отрывочен на этом основании и не чувствую себя слишком уверенным, что это должно быть то, что я использую пока.

У меня есть служба Kafka/Zookeeper, работающая без каких-либо проблем, и я хочу написать небольшую примерную программу, которая на основе ввода будет выписывать ее, но не делать wordcount, так как существует так много примеров уже.

Что касается выборочных данных, я получаю строку следующей структуры:

Примеры данных

This a sample string containing some keywords such as GPS, GEO and maybe a little bit of ACC.

Вопрос

Я хочу иметь возможность извлекать ключевые слова из 3 букв и печатать их с помощью System.out.println. Как получить строковую переменную, содержащую вход? Я знаю, как применять регулярные выражения или даже просто искать строку, чтобы получить ключевые слова.

Код

public static void main(String[] args) {
    Properties props = new Properties();
    props.put(StreamsConfig.APPLICATION_ID_CONFIG, "app_id");
    props.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "0:0:0:0:0:0:0:1:9092");
    props.put(StreamsConfig.ZOOKEEPER_CONNECT_CONFIG, "0:0:0:0:0:0:0:1:2181");
    props.put(StreamsConfig.KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
    props.put(StreamsConfig.VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());

    final Serde<String> stringSerde = Serdes.String();

    KStreamBuilder builder = new KStreamBuilder();

    KStream<String, String> source = builder.stream(stringSerde, stringSerde, "in-stream");

    KafkaStreams streams = new KafkaStreams(builder, props);
    streams.start();

    //How do I assign the input from in-stream to the following variable?
    String variable = ?
}

У меня есть zookeeper, kafka, производитель и потребитель, которые подключены к одной и той же теме, поэтому я хочу, чтобы в основном увидеть тот же самый String во всех экземплярах (производитель, потребитель и поток).

Ответ 1

Если вы используете Kafka Streams, вам необходимо применить функции/операторы к вашим потокам данных. В вашем случае вы создаете объект KStream, таким образом, вы хотите применить оператор к source.

В зависимости от того, что вы хотите сделать, есть операторы, которые применяют функцию к каждой записи в потоке независимо (например, map()), или другие операторы, которые применяют функцию к нескольким записям вместе (например, aggregateByKey()). Вы должны заглянуть в документацию: http://docs.confluent.io/3.0.0/streams/developer-guide.html#kafka-streams-dsl и примеры https://github.com/confluentinc/kafka- потоки-примеры

Таким образом, вы никогда не создаете локальные переменные, используя потоки Kafka, как показано в примере выше, а скорее встраиваете все в операторы/функции, которые объединяются в цепочки.

Например, если вы хотите распечатать все входные записи на стандартный вывод, вы можете сделать

KStream<String, String> source = builder.stream(stringSerde, stringSerde, "in-stream");
source.foreach(new ForeachAction<String, String>() {
    void apply(String key, String value) {
        System.out.println(key + ": " + value);
    }
 });

Таким образом, после того, как вы запустите свое приложение через streams.start(), оно будет использовать записи из вашей входной темы, и для каждой записи вашей темы будет выполнен вызов apply(...), который печатает запись в stdout.

Конечно, более естественным способом печати потока на консоль было бы использование source.print() (который внутренне в основном совпадает с показанным оператором foreach() с уже заданным ForeachAction.)

Для вашего примера с назначением строки локальной переменной вам нужно будет поместить свой код в apply(...) и выполнить там регулярные выражения и т.д., Чтобы "извлечь 3-буквенные ключевые слова".

Лучший способ выразить это, однако, был бы через комбинацию flatMapValues() и print() (то есть source.flatMapValues(...).print()). flatMapValues() вызывается для каждой входной записи (в вашем случае я предполагаю, что ключ будет null поэтому вы можете его игнорировать). В вашей функции flatMapValue вы применяете регулярное выражение и для каждого совпадения добавляете совпадение в список значений, которые вы в конечном итоге возвращаете.

source.flatMapValues(new ValueMapper<String, Iterable<String>>() {
    @Override
    public Iterable<String> apply(String value) {
        ArrayList<String> keywords = new ArrayList<String>();

        // apply regex to value and for each match add it to keywords

        return keywords;
    }
}

Выходом flatMapValues снова будет KStream, содержащий запись для каждого найденного ключевого слова (т. KStream Выходной поток представляет собой "объединение" по всем спискам, которые вы возвращаете в ValueMapper#apply()). Наконец, вы просто выводите свой результат на консоль с помощью print(). (Конечно, вы могли бы также использовать один foreach вместо flatMapValue + print но это было бы менее модульно.)