RxJava使用Window和Groupby在Flowable和Observable之间输出不同的输出

时间:2017-08-21 18:43:57

标签: kotlin reactive-programming rx-java2

我使用RxJava2代码可以归结为类似的东西:

val whitespaceRegex = Regex("\\s+")
val queryRegex = Regex("query=([^&]+)", RegexOption.IGNORE_CASE)
val dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME

@JvmStatic
fun main(args: Array<String>) {
    val cnt = AtomicLong()
    val templateStr = "|date| /ignored/ query=|query|"
    val random = ThreadLocalRandom.current()
    var curDate = ZonedDateTime.of(LocalDate.of(2016, Month.JANUARY, 1), LocalTime.MIDNIGHT, ZoneId.of("UTC"))

    val generator = Flowable.generate<String> { emitter ->
        // normally these are read from a file, this is for the example 
        val next = cnt.incrementAndGet()
        if (next % 3000 == 0L) {
            curDate = curDate.plusDays(1)
        }
        if (next < 100000) {
            val curStr = templateStr
                    .replace("|date|", dateTimeFormatter.format(curDate))
                    .replace("|query|", random.nextInt(1, 1000).toString())
            emitter.onNext(curStr)
        } else {
            emitter.onComplete()
        }

    }
    val source = generator
            .map { line ->
                val cols = line.split(whitespaceRegex)
                val queryRaw = queryRegex.find(cols[2])?.groupValues?.get(1) ?: ""
                val query = URLDecoder.decode(queryRaw, Charsets.UTF_8.name()).toLowerCase().replace(whitespaceRegex, " ").trim()
                val date = dateTimeFormatter.parse(cols[0])
                Pair(LocalDate.from(date), query)
            }
            .share()

    source
            .window(source.map { it.first }.distinctUntilChanged())
            .flatMap { window ->
                window
                        .groupBy { pair -> pair }
                        .flatMap({ grouping ->
                            grouping
                                    .count()
                                    .map {
                                        Pair(grouping.key, it)
                                    }.toFlowable()
                        })
            }
            .subscribe({ println("Result: $it}") }, { it.printStackTrace() }, { println("Done") })
}

当我使用Observable.generate时,它工作正常,但Flowable.generate没有输出。这计算在给定的一天发生了多少查询。这一天顺序增加,所以我形成了每天的窗口,然后用groupBy计算查询。我是否需要使用Flowable以不同方式执行此操作?

1 个答案:

答案 0 :(得分:0)

正如akarnokd所提到的,这是由于flatMap的默认maxConcurrency为128.我发现了这个问题https://github.com/ReactiveX/RxJava/issues/5126,它更详细地描述了原因。这解决了这个问题:

        val cnt = AtomicLong()
        val templateStr = "|date| /ignored/ query=|query|"
        val random = ThreadLocalRandom.current()
        var curDate = ZonedDateTime.of(LocalDate.of(2016, Month.JANUARY, 1), LocalTime.MIDNIGHT, ZoneId.of("UTC"))

        val generator = Flowable.generate<String> { emitter ->
            val next = cnt.incrementAndGet()
            if (next % 3000 == 0L) {
                curDate = curDate.plusDays(1)
            }
            if (next < 1000000) {
                val curStr = templateStr
                        .replace("|date|", dateTimeFormatter.format(curDate))
                        .replace("|query|", random.nextInt(1, 1000).toString())
                emitter.onNext(curStr)
            } else {
                emitter.onComplete()
            }

        }
        val source = generator
                .map { line ->
                    val cols = line.split(whitespaceRegex)
                    val queryRaw = queryRegex.find(cols[2])?.groupValues?.get(1) ?: ""
                    val query = URLDecoder.decode(queryRaw, Charsets.UTF_8.name()).toLowerCase().replace(whitespaceRegex, " ").trim()
                    val date = dateTimeFormatter.parse(cols[0])
                    Pair(LocalDate.from(date), query)
                }
                .share()

        source
                .window(source.map { it.first }.distinctUntilChanged().doOnEach({println("Win: $it")}))
                .flatMap( { window ->
                    window
                            .groupBy { pair -> pair }
                            .flatMap({ grouping ->
                                grouping
                                        .count()
                                        .map {
                                            Pair(grouping.key, it)
                                        }.toFlowable()
                            // fix is here
                            }, Int.MAX_VALUE)
                // and here
                }, Int.MAX_VALUE)
                .subscribe({ println("Result: $it}") }, { it.printStackTrace() }, { println("Done") })