package streamcruncher.test.func.generic; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.testng.Assert; import streamcruncher.api.artifact.RowSpec; import streamcruncher.api.artifact.RowSpec.Info; import streamcruncher.test.func.BatchResult; import streamcruncher.test.func.OrderGenenerator; /* * Author: Ashwin Jayaprakash Date: Dec 23, 2006 Time: 8:42:03 AM */ /** * <p> * This example along with {@link TopSellingItemsUpdateGroupTest} shows how * Chained Partitions and the "Highest X elements Window" can be used to keep * track of the top selling items in a Store. * <p> * <p> * Here, Orders are placed and the total quantities are stored at "Country > * State > City > Item SKU" level. The sum is a rolling-sum over a 30 day * period. Everytime the Sum changes, it is fed to the Partition down the chain, * which stores the top 3 products per Country/State/City, whose total * quantities exceed all other products. * </p> */ public abstract class TopSellingItemsTest extends OrderGenenerator { protected static final int windowSize = 3; private ArrayList<Object[]> data = initData(); private ArrayList<Object[]> initData() { ArrayList<Object[]> list = new ArrayList<Object[]>(); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 10, null, 1L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 10, null, 2L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 3, null, 3L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 11, null, 4L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 1, null, 5L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 4, null, 6L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 50, null, 7L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 20, null, 8L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 3, null, 9L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 7, null, 10L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 8, null, 11L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 9, null, 12L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 2, null, 13L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 3, null, 14L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 1, null, 15L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 90, null, 16L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 48, null, 17L }); list.add(new Object[] { "US", "California", "San Jose", "ansible", 4800, null, 19L }); list.add(new Object[] { "US", "California", "San Jose", "nano-mech", 90000, null, 20L }); list.add(new Object[] { "US", "California", "San Jose", "reentry-tile", 4800, null, 21L }); list.add(new Object[] { "US", "California", "San Jose", "niling-dsink", 4800, null, 22L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 10, null, 23L }); list.add(new Object[] { "US", "California", "San Jose", "niling-dsink", 1200, null, 24L }); return list; } @Override protected int getMaxDataRows() { return data.size(); } @Override protected String[] getResultColumnNames() { return new String[] { "country", "state", "city", "item_sku", "sum_item_qty" }; } @Override protected String[] getColumnTypes() { /* * "country", "state", "city", "item_sku", "item_qty", "order_time", * "order_id" */ return new String[] { RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), java.lang.Integer.class.getName(), java.sql.Timestamp.class.getName(), java.lang.Long.class.getName() }; } @Override protected String[] getResultColumnTypes() { return new String[] { RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), RowSpec.addInfo(java.lang.String.class.getName(), Info.SIZE, 15), java.lang.Double.class.getName() }; } @Override protected void afterEvent(int counter) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(System.err); } } protected Iterator<Object[]> getData() { Iterator<Object[]> iter = new Iterator<Object[]>() { private int counter = 1; public boolean hasNext() { return counter <= getMaxDataRows(); } public Object[] next() { /* * "country", "state", "city", "item_sku", "item_qty", * "order_time", "order_id" */ Object[] event = data.get(counter - 1); event[5] = new Timestamp(TopSellingItemsTest.this.getEventTimeStamp(counter)); System.out.println(Arrays.asList(event)); counter++; return event; } /** * @throws UnsupportedOperationException */ public void remove() { throw new UnsupportedOperationException(); } }; return iter; } @Override protected String getRQL() { String csv = getRQLColumnsCSV(); return "select " + csv + " from test" + " (partition by country, state, city, item_sku store last 30 days with sum(item_qty) as sum_item_qty)" + " to" + " (partition by country, state, city store highest " + windowSize + " using sum_item_qty where $row_status is new) as test_str" + " where test_str.$row_status is not dead;"; } @Override protected void verify(List<BatchResult> results) { System.out.println("--Results--"); for (BatchResult result : results) { System.out.println("Batch created at: " + new Timestamp(result.getTimestamp()) + ". Rows: " + result.getRows().size()); List<Object[]> rows = result.getRows(); Assert.assertTrue((rows.size() <= windowSize), "Window size does not match expected count"); System.out.println(" Batch results"); for (Object[] objects : rows) { System.out.print(" "); for (Object object : objects) { System.out.print(object + " "); } System.out.println(); } } BatchResult lastResult = results.get(results.size() - 1); List<Object[]> rows = lastResult.getRows(); Assert.assertEquals(rows.size(), windowSize, "Top X items do not match expected count"); HashMap<String, Object> values = new HashMap<String, Object>(); for (Object[] objects : rows) { String itemSKU = (String) objects[3]; Double sum = (Double) objects[4]; Object oldVal = values.get(itemSKU); if (oldVal == null) { values.put(itemSKU, sum); } else { values.put(itemSKU, new Object[] { oldVal, sum }); } } Assert.assertEquals(values.get("nano-mech"), 90000.0D, "Nano-Mech sum not present or not matching"); Object dsink = values.get("niling-dsink"); Assert.assertTrue(dsink != null, "Niling-DSinks sums not present"); Object[] dsinks = (Object[]) dsink; Double d1 = (Double) dsinks[0]; Double d2 = (Double) dsinks[1]; Assert.assertTrue((d1 != d2), "Niling-DSink values should not be equal"); Assert.assertTrue((d1 + d2 == 10800), "Niling-DSink sum does not match expected value"); } }