Статьи

Как реализовать сложные бизнес-правила с помощью мощного инструмента вычислений

В постоянно меняющемся деловом мире люди в наши дни часто оказываются зацикленными на различных компьютерных проблемах, связанных со сложными бизнес-правилами. Рассмотрим приведенный ниже пример:

1. На основе деталей заказа найдите 10 лучших покупателей в каждом месяце 2012 года.

2. Средний остаток на счету тех клиентов, которые когда-то купили все товары.

3. Вычислите ежемесячную скорость роста стоимости контракта, установленную каждым продавцом.

4. На основании ежедневной торговой статистики по нескольким акциям определите, что акции растут в течение 5 дней подряд.

Для большинства людей SQL может быть их первой идеей в решении сложных вычислений для больших данных. Это правда, что SQL реализует различные типичные вычисления больших данных с обильными ресурсами и широким спектром приложений. Однако, когда речь идет о сложных бизнес-правилах, SQL, очевидно, весьма неудобен, поскольку SQL не предлагает прямой поддержки пошагового механизма , не поддерживает явные наборы , упорядоченные наборы и не имеет ссылки на объект. ,

Нет прямой поддержки пошаговых вычислений . Упорядочение, упрощение и поэтапное уточнение является важным методом решения сложных проблем. Эта передовая практика также применима к бизнес-вычислениям по необычно сложным бизнес-правилам. Тем не менее, SQL не предоставляет прямой поддержки для пошаговых вычислений. Другими словами, пользователи SQL должны составить одно длинное утверждение, чтобы решить любую сложную проблему, добавив трудности при разработке, понимании и обслуживании кодирования.

Тем не менее, пример 1, основанный на деталях заказа, находит 10 лучших покупателей в каждом месяце 2012 года. Решение SQL:

select Client from(

  select * from(

  select B.*,row_number() over(partition by month order by SumValue desc)

  rown from(

  select to_char(SellDate,'mm') month,Client,sum(Quantity*Amount) SumValue

   from contract

  where SellDate>=to_date('2012-01-01','yyyy-mm-dd')

  and SellDate<=to_date('2012-12-31','yyyy-mm-dd')

  group by to_char(SellDate,'mm'),Client order by month,client

  ) B

  )C

  where rown<=10

)D

group by Client

having count(Client)=(

  select  count(distinct(to_char(SellDate,'mm')))

  from contract

  where SellDate>=to_date('2012-01-01','yyyy-mm-dd')

  and SellDate<=to_date('2012-12-31','yyyy-mm-dd')

)

Как вычислительный инструмент, превосходящий других по обработке сложных бизнес-правил, в качестве базовой функции предполагается пошаговое вычисление. Для той же проблемы esPoc может реализовать это так:

Cell A1: Filter out the data for year 2012 by date

Cell A2: Group A1 result by month

Cell A3: Compute the monthly sales of each clients, based on the A2 result

Cell A4: Sort clients by sales in reverse order, based on the A3 result

Cell A5: Filter out the top 10 greatest buyers for each month, based on the A4 result

Cell A6: Retrieve the client IDs for each month, based on the A5 result

Cell A7: Find the top 10 buyers in each month by computing the intersection set for each month, based on the A6 result

Как видно, esProc может разбить сложную задачу на несколько компонентов, чтобы выполнить ее за несколько простых шагов. Сложная проблема может быть решена путем упрощения и поэтапного уточнения.

Нет поддержки явного набора. Явные множества являются переменными явного типа множества. Хотя SQL поддерживает алгоритм множеств, нет такого типа данных, как в SQL, не говоря уже о явном наборе. Многие алгоритмы должны быть реализованы со специальной тактикой.

Предыдущий пример также касается операций на множестве. Способ найти топ-10 для каждого месяца — это просто операция пересечения для топ-10 покупателей в каждом месяце. Код esProc — это A6.isect (), представляющий пересечение — то есть вычисление isect — для проведения над верхними 10 для каждого месяца как то, что вычисляется в A6. Решение и бизнес-логика одинаково совпадают, в то время как решение задачи пересечения с помощью SQL-решения во многом зависит от идей зомбирования и зомбирования:

1. Сгруппируйте по месяцам, а затем посчитайте группы.

2. Сгруппируйте по КЛИЕНТУ и посчитайте вхождения каждого КЛИЕНТА.

3. Выберите тех КЛИЕНТОВ, для которых количество в 2 равно количеству в 1.

Очевидно, что даже опытные программисты могут не понять этот хитрый метод, который, насколько нам известно, является самым простым решением.

Затем давайте рассмотрим другой пример, чтобы найти контракты, отвечающие следующим условиям:

1. Все контракты

2. Контракты, заключенные в 2012 году

3. Заказано более 40 наименований (большое количество)

4. Цена за единицу более 2000 (отличная цена за единицу)

5. Выполнение условий 2 — 4

6. Исключая тех, которые удовлетворяют условию 5

Код SQL показан ниже:

1. выберите SellDate, количество, сумму, клиент из контракта

2. выберите SellDate, количество, сумму, клиент из контракта, где to_char (SellDate, ‘yyyy’) = ‘2012’

3. выберите SellDate, количество, сумму, клиент из контракта, где количество> = 40

4. выберите SellDate, количество, сумму, клиент из контракта, где AMOUNT> = 2000

5. выберите SellDate, количество, сумму, клиент из контракта, где to_char (SellDate, ‘yyyy’) = ‘2012’ и количество> = 40 и AMOUNT> = 2000

6. выберите SellDate, количество, сумму, клиент из контракта, где нет (to_char (SellDate, ‘yyyy’) = ‘2012’ и количество> = 40 и AMOUNT> = 2000)

В отличие от SQL, esProc поддерживает явный набор по своей природе, поддерживая естественную и ясную мысль о дизайне, более простом кодировании и более высокой читабельности. Решить вышеуказанную проблему b с помощью esProc так просто, как показано ниже в ее впечатляющем коде:

Примечание: A1-A6 для условий 1-6.

Явный набор может использоваться в сочетании с пошаговым вычислением. Например, на основе результата примера 1, рассчитать стоимость контракта в месяц для клиентов, которые не входят в первую десятку покупателей. Пользователям esProc нужно добавить только одну инструкцию: (A4 \\ A5). (~ .sum (SumValue)).

Для сравнения, пользователи SQL должны полностью изменить решение:

with A as (

  select SellDate,Quantity,Amount,Client from contract

  where SellDate>=to_date('2012-01-01','yyyy-mm-dd')

  and SellDate<=to_date('2012-12-31','yyyy-mm-dd')

),B as(

  select to_char(SellDate,'mm') month,Client,sum(Quantity*Amount) SumValue

  from A group by to_char(SellDate,'mm'),Client order by month,client

)

,C as(

  select B.*,row_number() over(partition by month order by SumValue desc)rown

  from B

),D as(

  select * from C where rown<=10

)

select sum(sumValue) monthValue from(

  select * from C

  MINUS

  select * from D

)group by month order by month

Отсутствие ссылки на объект . Как известно, группу релевантных данных можно рассматривать как объект. Таким образом, мы можем воспользоваться ссылкой на объект, чтобы представить отношение данных интуитивно и просто. Благодаря этому сложность вычислений, связанных с ассоциациями, может быть безвременна уменьшена. Сложность SQL в основном связана с отсутствием поддержки ссылки на объект. Программистам всегда сложно найти интуитивно понятный способ интуитивно представить взаимосвязи между данными. Как показано в примере 2, чтобы найти Клиента, который однажды купил все товары, и усреднить их соответствующие остатки на счетах, способ решения проблемы может быть:

1. Найдите соответствующие заказы, соответствующие каждому клиенту, и найдите элементы в деталях заказа, ссылаясь на заказы.

2. Вычислите уникальное значение для каждого элемента, затем подсчитайте отдельное значение, чтобы иметь длину списка купленных элементов для каждого клиента

3. Просто сравнивая длины списка купленных товаров и стандартного списка товаров, мы можем найти клиентов, отвечающих этим условиям.

Решение SQL выглядит следующим образом:

with A as(

  select orders.order_id,orders.customer_id,orderdetails.item_id

  from orders left join orderdetails

  on orders.order_id=orderdetails.order_id

),B as(

  select customer_id,count(distinct(item_id))ItemCount

  from A group by customer_id

  having count(distinct(item_id))=(select count(item_id) from item)

)

select avg(customers.acct_balance) from B left join customers

on B.customer_id=customers.customer_id

Как видно из вышеизложенного, даже не очень длинный SQL-оператор, представленный выше, трудно понять, учитывая несколько соединений. Из всех этих заумных моментов ключевым моментом является «определение местоположения соответствующих заказов для каждого клиента и соответствующих товаров с помощью ссылок на заказы». Для сравнения, благодаря встроенной поддержке esProc для ссылки на объект, пользователи esProc могут использовать оператор «.» для доступа к данным напрямую. Для этих заумных моментов esProc может ясно выразиться так: cGroup. (Order_id). (Item_id). В котором «cGroup» представляет каждого клиента, «. (Order_id)» заказы, соответствующие клиентам, и «. (Item_id)» позиции, соответствующие заказам.

Для дальнейшего вычисления и подсчета отдельного значения после связывания, код esProc имеет вид cGroup. (Order_id). (Item_id) .id (). Count ().

Простая ассоциация, интуитивный доступ и понятная логика — они являются преимуществами ссылки на объект.

Нет поддержки для заказанного набора. Сложные бизнес-правила часто связаны с упорядоченными вычислениями, такими как сравнение по месяцам, сравнение относительных соотношений ссылок, поиск данных в относительном диапазоне, ранжирование в группах или вычисление первых или последних. Возьмите пример 3 для расчета ежемесячного прироста стоимости контракта для каждого продавца (ACTUALSALE). Решение SQL:

with A as(

  select actualSale,Quantity*Amount sales,sellDate from contract

),B as(

  select actualSale,TO_NUMBER(to_char(SellDate,'yyyy')) year,

  TO_NUMBER(to_char(SellDate,'mm')) month,

  sum(sales) salesMonth

  from A group by actualSale,TO_NUMBER(to_char(SellDate,'yyyy')) ,

  TO_NUMBER(to_char(SellDate,'mm'))

  order by actualSale,year,month

),C as(

  select actualSale,year, month, salesMonth,

  lag(salesMonth,1,0) over(order by actualSale,year,month) prev_salesMonth,

  lag(actualSale,1,0) over(order by actualSale) prev_actualSale

  from B

)

select actualSale,prev_actualSale,year, month,

   (case when prev_salesMonth!=0 and

  actualSale=prev_actualSale 

  then ((salesMonth/prev_salesMonth)-1)

  else 0

  end)LRR

from C

In which, the most difficult part is to present the month-over-month sales comparison for each sales man with SQL. With the native support for ordered set, esProc enable programmers to simply put this algorithm as salesMonth/salesMonth[-1]-1, in which the salesMonth represents the sales of this month, and salesMonth[-1] the sales of the previous month.

For another example, to find the top 3 salesman having achieved the greatest sales values, esProc users can simply put it like this: A2.sort(-sum(SALES)).select(#<3). For the computations related to range and order, such as the moving average of salesman in 3 months, esProc users can simply write: salesMonth{-1,1}.avg().

These algorithms are never easy for SQL to implement.

As can be seen, with the supports for step-by-step computation, object reference, and ordered set, esProc can implement the complex business rules easily.

Needless to say, some other computing languages may offer one or several above-mentioned features. For example, Java, C#, and other high-level languages support the step-by-step computation, object reference, and other features well. However, the high-level languages also have the obvious drawbacks: neither do they have enough basic function libraries, nor are their computing capabilities dedicated and purpose-designed. To have a clear insight about this fact, let’s try to compute the moving average with Java: 

  ......

  st=conn.prepareStatement("select sum(amount)amount, to_char(time,'MM')month from loan  where to_char(time,'yyyy')=to_char(sysdate,'yyyy') group by to_char(time,'MM') order by month",ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

  ResultSet rs=st.executeQuery();

  int size=rs.getFetchSize();

  for(int currentPos=1;currentPos<=size;currentPos++){

  rs.absolute(currentPos);

  float preAmount=-1,thisAmount=-1,nextAmount=-1;

  float avgAmount=-1;

  String month=rs.getString("month");

    thisAmount=rs.getFloat("amount");

  if(currentPos==1){ 

  rs.next();

  nextAmount=rs.getFloat("amount");

  avgAmount=(thisAmount+nextAmount)/2;

  }elseif(currentPos==size){

  rs.previous();

  preAmount=rs.getFloat("amount");

  avgAmount=(thisAmount+preAmount)/2;

  }else{

  rs.previous();

  preAmount=rs.getFloat("amount");

  rs.next();

  rs.next();

  nextAmount=rs.getFloat("amount");

  avgAmount=(thisAmount+nextAmount+preAmount)/3;

  }

  System.out.println(month+"  "+avgAmount);

  }

  rs.close();

  …… Как видно выше, Java и другие языки высокого уровня подходят для разработки базовых библиотек функций или утилит, но не подходят для структурных вычислений данных. Они особенно неудобны в реализации вычислений, включающих сложные бизнес-правила.

The R language is a scientific computing tool and characterized with the step-by-step computation, explicit set, objects reference, and ordered set. With the four advantages, R is more adept to solve the complex computation involving complex business rules. However, it is a pity that R users are mainly the scientific researchers because R syntax and function is too specialized for the average programmer to use. For example, in the example case 4, with the daily trading data, select the stocks which have been rising for 5 consecutive days from multiple stocks. The codes of R are:

01  library(gdata) #use excel function library

02  A1<- read.xls("e:\\data\\all.xlsx") #import data

03  A2<-subset(A1,as.POSIXlt(Date)>=as.POSIXlt('2012-06-01') & as.POSIXlt(Date)<=as.POSIXlt('2012-06-30')) #filter by date

04  A3 <- split(A2,A2$Code) #group by Code

05  A8<-list()

06  for(i in 1:length(A3)){

07    A3[[i]][order(as.numeric(A3[[i]]$Date)),] #sort by Date in each group

08    A3[[i]]$INC<-with(A3[[i]], Close-c(0,Close[- length (Close)])) #add a column, increased price

09    if(nrow(A3[[i]])>0){  #add a column, continuous increased days

10    A3[[i]]$CID[[1]]<-1

11    for(j in 2:nrow(A3[[i]])){

12    if(A3[[i]]$INC[[j]]>0 ){

13    A3[[i]]$CID[[j]]<-A3[[i]]$CID[[j-1]]+1

14    }else{

15    A3[[i]]$CID[[j]]<-0

16    }

17    } 

18    }

19    if(max(A3[[i]]$CID)>=5){  #stock max CID is bigger than 5

20    A8[[length(A8)+1]]<-A3[[i]]

21    }

22  }

23  A9<-lapply(A8,function(x) x$Code[[1]]) #finally,stock code

esProc features the agile syntax, strong presentation, and much friendlier mechanism to follow the natural thought pattern of programmers and help them solve the above problems effortlessly.

In addition, the code of esProc is presented in a grid, which is intuitive for presenting the step-by-step computation and convenient for code debugging. In esProc, users can set the break point, run step by step, and run to cursor. When debugging, users can monitor the computing result of the current cell, and review every executed cells at any time. All these conveniences are the result of true debugging.

R lacks the true invoking mechanism, and only provides the very inconvenient console command for calling. 

R is poor when integrating to other tools. Because it is designed for scientists to use on desktop, it is hard to integrate R with reporting tools or high-level languages like JAVA and C#.

The library function of R is quite good. But R language is poor in implementing the loops with acceptable performance. Looping for 100 million times would cost over 1 hour to complete. Considering the facts that the data traversal is very common for the business computing involving complex business rules, and not all jobs can be done with library function, R language currently is not a practical tool for handling big data with such poor performance.

esProc provides the JDBC interface for integration into the reporting tool or Java applications. Regarding the performance, esProc is comparable to the popular interpreting scripts like Perl and Python, and superior to R language by one order of magnitude. In addition, esProc allows for the inexpensive scale-out to meet the high demand on big data computing.