Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
 Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
Привет котики.

Давайте раскачаем возможности и недостатки reduce/collect.

1) Дана табличка (из аэропорта)
     Column      |         Type          
-----------------+-----------------------+
 aircraft_code   | character(3)          |
 seat_no         | character varying(4)  |
 fare_conditions | character varying(10) |

Entity:
@Data
public class Seat {
    private String aircraftCode;
    private String seatNo;
    private String fareConditions;
}


Образец данных.

aircraft_code seat_no fare_conditions
319 2A Business
319 2C Business
319 2D Business
319 2F Business
319 3A Business
319 3C Business
319 3D Business
319 3F Business
319 4A Business
319 4C Business


2) С помощью Stream-API получить из нее отчет по
количеству мест бизнес класса и других типов комфорта
с группировкой по aircraft_code.

Пример отчота.
aircraft_code  |             fare_conditions             
---------------+-----------------------------------------
 319           | Business(20), Economy(96)
 320           | Business(20), Economy(120)
 321           | Business(28), Economy(142)
 733           | Business(12), Economy(118)
 763           | Business(30), Economy(192)
 773           | Business(30), Comfort(48), Economy(324)
 CN1           | Economy(12)
 CR2           | Economy(50)
 SU9           | Business(12), Economy(85)
(9 rows)


Исходные данные для пояснения https://postgrespro.ru/education/demodb

Go-go кодить!
14 мар 20, 19:40    [22099128]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
Valentin Kolesnikov
Member

Откуда:
Сообщений: 3264
mayton,

Я не котик если чо.

Хорошего вам дня!
14 мар 20, 21:22    [22099173]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
Как будет угодно.

Primary goal: посмотреть как выглядит аналитка на Stream::API

Secondary goal: тоже самое я хочу попробовать на Spark/Scala. Насколько будет лучше-хуже.
Если хватит сил и времени.
14 мар 20, 21:44    [22099176]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
chpasha
Member

Откуда:
Сообщений: 9039
в стримах не эксперт, навалял как мог :) .

Stream.of(
                new Seat("309", "1", "Business"),
                new Seat("309", "2", "Business"),
                new Seat("309", "3", "Economy"),
                new Seat("309", "4", "Comfort"),
                new Seat("C01", "1", "Economy"),
                new Seat("C01", "2", "Economy"),
                new Seat("C03", "1", "Business")
        ).collect(
                groupingBy(Seat::getAircraftCode, TreeMap::new,
                        groupingBy(Seat::getFareConditions, TreeMap::new, counting()))
        ).forEach(
                (flight, seatsByComfort) -> System.out.println(String.format("%s: %s", flight, seatsByComfort.entrySet().stream().reduce(
                                new StringBuilder(),
                                (sb, entry) -> sb.append(String.format("%s%s (%s)", sb.length() > 0 ? ", " : "", entry.getKey(), entry.getValue())),
                                StringBuilder::append)
                        )
                )
        );

Output:

309: Business (2), Comfort (1), Economy (1)
C01: Economy (2)
C03: Business (1)
14 мар 20, 21:56    [22099177]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
chpasha

        ).forEach(
                (flight, seatsByComfort) -> System.out.println(String.format("%s: %s", flight, seatsByComfort.entrySet().stream().reduce(
                                new StringBuilder(),
                                (sb, entry) -> sb.append(String.format("%s%s (%s)", sb.length() > 0 ? ", " : "", entry.getKey(), entry.getValue())),
                                StringBuilder::append)
                        )
                )
        );


Шикарно. Только вот эта последняя часть - некрасивая. Но здесь я виноват т.к. поставил задачу вида отчот.

Было-бы хорошо получить не поток символов StringBuilder а поток энтитей виде строка отчота.
Я понимаю что эта глупая группировка

773           | Business(30), Comfort(48), Economy(324)


ломает естественный порядок.

Давайте упростим задачу здесь. Но поставим немного другой - более табличный отчот.

Пускай будет 3 строки вида.

773           | Business(30), 
773           | Comfort(48), 
773           | Economy(324)
14 мар 20, 22:04    [22099181]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
SpringMan
Member

Откуда:
Сообщений: 139
На скале наваял:
  def simpleGroup(): Unit = {
    case class Seat(aircraftCode: String, seatNo: String, fareConditions: String)

    Seq(
      Seat("309", "1", "Business"),
      Seat("309", "2", "Business"),
      Seat("309", "3", "Economy"),
      Seat("309", "4", "Comfort"),
      Seat("C01", "1", "Economy"),
      Seat("C01", "2", "Economy"),
      Seat("C03", "1", "Business")
    )
      .groupBy(seat => (seat.aircraftCode, seat.fareConditions))
      .map { case ((aircraftCode, fareConditions), seats) => (aircraftCode, fareConditions, seats.length) }
      .foreach(println)
  }

Для спарка почти буква в букву будет
14 мар 20, 22:32    [22099191]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
chpasha
Member

Откуда:
Сообщений: 9039
ну если у нас есть "строка отчета", то, допустим, так

 Stream.of(
                new Seat("309", "1", "Business"),
                new Seat("309", "2", "Business"),
                new Seat("309", "3", "Economy"),
                new Seat("309", "4", "Comfort"),
                new Seat("C01", "1", "Economy"),
                new Seat("C01", "2", "Economy"),
                new Seat("C03", "1", "Business")
        ).collect(
                groupingBy(Seat::getAircraftCode, TreeMap::new,
                        groupingBy(Seat::getFareConditions, TreeMap::new, counting()))
        ).entrySet()
              .stream()
              .flatMap(entry -> entry.getValue().entrySet().stream().reduce(
                      new ArrayList<ReportEntry>(),
                      (arr, val) -> combine(arr, new ReportEntry(entry.getKey(), String.format("%s (%s)", val.getKey(), val.getValue()))),
                      this::combine).stream())
              .forEach(System.out::println);

Output (поленился переписывать toString или раширять последний forEach)

ReportEntry(aircraftCode=309, fareConditions=Business (2))
ReportEntry(aircraftCode=309, fareConditions=Comfort (1))
ReportEntry(aircraftCode=309, fareConditions=Economy (1))
ReportEntry(aircraftCode=C01, fareConditions=Economy (2))
ReportEntry(aircraftCode=C03, fareConditions=Business (1))


пришлось еще ввести две функции combine для reduce, чтобы лаконично добавлять элемент к List и тут же этот List возвращать, по-моему в java se по-другому никак короче не запишешь (ну и вообще рабочий код я бы в таком виде не оставлял - как минимум flatmap и reduce в отдельные функции с говорящими названиями)
14 мар 20, 22:39    [22099195]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
О спасибо. Надо теперь что-то придумать с WINDOWS functions. Но применительно к аэропорту я ничего не могу
придумать материального и имеющего смысл.
14 мар 20, 23:43    [22099213]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
asv79
Member

Откуда: Тверь
Сообщений: 2991
chpasha
ну если у нас есть "строка отчета", то, допустим, так

 Stream.of(
                new Seat("309", "1", "Business"),
                new Seat("309", "2", "Business"),
                new Seat("309", "3", "Economy"),
                new Seat("309", "4", "Comfort"),
                new Seat("C01", "1", "Economy"),
                new Seat("C01", "2", "Economy"),
                new Seat("C03", "1", "Business")
        ).collect(
                groupingBy(Seat::getAircraftCode, TreeMap::new,
                        groupingBy(Seat::getFareConditions, TreeMap::new, counting()))
        ).entrySet()
              .stream()
              .flatMap(entry -> entry.getValue().entrySet().stream().reduce(
                      new ArrayList<ReportEntry>(),
                      (arr, val) -> combine(arr, new ReportEntry(entry.getKey(), String.format("%s (%s)", val.getKey(), val.getValue()))),
                      this::combine).stream())
              .forEach(System.out::println);

Output (поленился переписывать toString или раширять последний forEach)

ReportEntry(aircraftCode=309, fareConditions=Business (2))
ReportEntry(aircraftCode=309, fareConditions=Comfort (1))
ReportEntry(aircraftCode=309, fareConditions=Economy (1))
ReportEntry(aircraftCode=C01, fareConditions=Economy (2))
ReportEntry(aircraftCode=C03, fareConditions=Business (1))


пришлось еще ввести две функции combine для reduce, чтобы лаконично добавлять элемент к List и тут же этот List возвращать, по-моему в java se по-другому никак короче не запишешь (ну и вообще рабочий код я бы в таком виде не оставлял - как минимум flatmap и reduce в отдельные функции с говорящими названиями)

неплохо
15 мар 20, 18:06    [22099463]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
crutchmaster
Member

Откуда: оттуда.
Сообщений: 948
mayton
Давайте раскачаем возможности и недостатки reduce/collect.

Делаю всё на map/reduce (правда в js) брат жив. Да, это дольше, чем написать group by и данные должны влазить в память целиком, НО возможностей и пространства для манёвров гораздо больше, чем может дать sql.
Быдлокод:
var rec = function(code, seat, cond) {return {code, seat, cond}};
var log = console.log;
var data = [
    rec("309", 1, "buisness"),
    rec("309", 2, "buisness"),
    rec("309", 3, "economy"),
    rec("309", 4, "confort"),
    rec("C01", 1, "economy"),
    rec("C01", 2, "economy"),
    rec("C03", 1, "buisness")
]
var report = data.reduce((s,v)=>{
    var r = s[v.code] = s[v.code] || {};
    r[v.cond] = r[v.cond] || 0;
    r[v.cond]++;
    return s;
},{});
Object.entries(report).forEach(([code,v])=>{
    var sums = Object.entries(v).map(([cond, sum]) s=>`${cond} (${sum})).join(",");
    log(`${k} : ${sums}`);
});
/*
309 : buisness(2),economy(1),confort(1)
C01 : economy(2)
C03 : buisness(1)
*/


upd: для Стасяна: это не значит, что sql не нужен вообще. Тупая группировка на sql отработает быстрее, чем ты сначала будешь гнать всю таблицу по сети, потом её парсить, гнать в pojo и через стрим.

Сообщение было отредактировано: 16 мар 20, 05:20
16 мар 20, 05:14    [22099596]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 4454
crutchmaster,
Конечно. Больше кода в аппСервере или бд определяется чисто _политикой_ организации где работаешь.
Можно и так и так.
16 мар 20, 08:33    [22099627]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
asv79
Member

Откуда: Тверь
Сообщений: 2991
crutchmaster


upd: для Стасяна: это не значит, что sql не нужен вообще. Тупая группировка на sql отработает быстрее, чем ты сначала будешь гнать всю таблицу по сети, потом её парсить, гнать в pojo и через стрим.

вопрос в том,насколько часто ты будешь лазить в базу- обычно все это кладется в кэш и уже оттуда тянется
16 мар 20, 09:17    [22099640]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
crutchmaster
Member

Откуда: оттуда.
Сообщений: 948
asv79
обычно все это кладется в кэш

Ну если у тебя цветочный магазин на 10 позиций, то, конечно, можно всё засунуть в кэш.
16 мар 20, 09:23    [22099641]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 4454
asv79
кладется

Вадя в любой проект кладет сокеты.
Ты получается в любой "попадание в кэш".
16 мар 20, 09:31    [22099644]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
crutchmaster, SQL может работать плохо когда мы транспонируем табличку и роли строк-столбцов
меняются местами. В этом случае императивный ЯП - лучше. Или не дай бог идет алгебра матриц.

В остальных случаях разработчик отчотов быстрее справляется с задачей на SQL чем даже
продвинутый кодер на обычном ЯП которому только ПРЕДСТОИТ реализовать какую-то
функцию квартиля или процентиля с ROLLUP в то время как СКЛ-щик имеет это сразу
из коробки и в виде DSL.

Но топи не про это. Я сейчас ковыряю Spark. И пытаюсь понять что я НЕ смогу на нем сделать.
16 мар 20, 11:57    [22099750]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
crutchmaster
Member

Откуда: оттуда.
Сообщений: 948
mayton
ЯП которому только ПРЕДСТОИТ реализовать какую-то
функцию квартиля или процентиля с ROLLUP в то время как СКЛ-щик имеет это сразу
из коробки и в виде DSL.

Так они тоже могут быть готовые в составе какой-нибудь либы и всё что надо это перегнать структуры в нужный вид. И потом, зайти тут в раздел субд и попробуй сходу понять что делает их 10-и этажный sql запрос, причём там нет какой-то тёмной магии анал.функций, а всякая банальщина типа выборки по интервалам или наркомания типа сложить последнюю запись с первой и отнять вторую. На тупой императивщене это просто выглядит понятнее и поддерживается легче а в sql портянки даже тот sql кодер уже через месяц не захочет лезть и начнёт мазаться, что "ничего нельзя сделать" (наблюдаю эту картину регулярно).

mayton
И пытаюсь понять что я НЕ смогу на нем сделать.

То, для чего он совсем не предназначен и то, что не влезет в память. Последнее решается разбиением запроса на куски и я не могу придумать схожу что-то настолько жирное что надо было бы делать целиком в субд.
16 мар 20, 12:34    [22099785]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
Сортировки и группировки. Это убивает память. Двигатели которые инкапсулированы в dbms обычно
знают об этом и используют внешние структуры данных (temporary-tables) для генерации резалт-сета
внутри этих структур. Программисты императивных языков берут коллекции и обычно видят OOM
пост-фактум. Тоесть когда это уже случилось.

Но не будем о грустном. Сегодня мне надо сделать шаблончик проекта на ApacheSpark под амазонский
сервис.
16 мар 20, 13:19    [22099837]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
mayton
Member

Откуда: loopback
Сообщений: 45379
А как из этого Аэропорта посохранять таблички в CSV ? Кто постгресщик?
16 мар 20, 13:32    [22099852]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 4454
mayton
А как из этого Аэропорта посохранять таблички в CSV ? Кто постгресщик?
разверни вопрос. CSV это текстовый формат файла.
16 мар 20, 13:37    [22099856]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
asv79
Member

Откуда: Тверь
Сообщений: 2991
crutchmaster
asv79
обычно все это кладется в кэш

Ну если у тебя цветочный магазин на 10 позиций, то, конечно, можно всё засунуть в кэш.

скажи это разрабам микросервисов
16 мар 20, 13:47    [22099869]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 4454
asv79
скажи это разрабам микросервисов
а ты не упоминай в приличном обществе этот флейм-слово.
16 мар 20, 13:52    [22099878]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
asv79
Member

Откуда: Тверь
Сообщений: 2991
PetroNotC Sharp
asv79
скажи это разрабам микросервисов
а ты не упоминай в приличном обществе этот флейм-слово.

сказать так ,что кеширование применяется только в цветочных магазинах с 10 запросами в минуту мог только такой же дилетант как ты петро)))
ваш выход)
16 мар 20, 13:57    [22099887]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 4454
asv79,
Ты вроде один такой, с цветочным магазином.
На сегодня ты уже перестал кодить.
16 мар 20, 13:58    [22099891]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
asv79
Member

Откуда: Тверь
Сообщений: 2991
PetroNotC Sharp
asv79,
Ты вроде один такой, с цветочным магазином.
На сегодня ты уже перестал кодить.

петро ты от жизни отстал
давно уже накожено и перекожено)
16 мар 20, 14:05    [22099901]     Ответить | Цитировать Сообщить модератору
 Re: Субботняя бухтелка по Stream::reduce/collect  [new]
PetroNotC Sharp
Member

Откуда:
Сообщений: 4454
asv79
PetroNotC Sharp
asv79,
Ты вроде один такой, с цветочным магазином.
На сегодня ты уже перестал кодить.

петро ты от жизни отстал
давно уже накожено и перекожено)
22099641
16 мар 20, 14:11    [22099908]     Ответить | Цитировать Сообщить модератору
Все форумы / Java Ответить