package streamcruncher.test.func.generic; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import org.testng.Assert; import streamcruncher.api.StreamCruncherException; import streamcruncher.api.TimeWindowSizeProvider; import streamcruncher.api.WindowSizeProvider; import streamcruncher.api.artifact.RowSpec; import streamcruncher.api.artifact.RowSpec.Info; import streamcruncher.test.func.BatchResult; /* * Author: Ashwin Jayaprakash Date: Feb 6, 2007 Time: 4:54:02 PM */ /** * <p> * This Test demonstrates the use of the {@link WindowSizeProvider} and the * {@link TimeWindowSizeProvider}, which can be used to modify the default size * of the Window for a particular sub-Window in a Partition. * </p> * <p> * Here, the Partition is created at the Item-SKU level and the * {@link CustomWindowSizeProvider} is used to alter the Time Window duration * and the maximum size for the "force-field" sub-Windows. "force-field" Events * are put into sub-Windows in the Partition where they do not expire for the * duration of the Test, while the other Events like "warp-drive" SKUs use the * default values. * </p> */ public abstract class TimeWFPartitionWinSizeProviderTest extends TimeWF1PartitionTest { private ArrayList<Object[]> data = initData(); private ArrayList<Object[]> initData() { ArrayList<Object[]> list = new ArrayList<Object[]>(); list.add(new Object[] { "US", "California", "San Jose", "force-field", 10, null, 1L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "force-field", 10, null, 2L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "force-field", 3, null, 3L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "force-field", 11, null, 4L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "force-field", 1, null, 5L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 4, null, 6L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 50, null, 7L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 20, null, 8L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 3, null, 9L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "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[] { "India", "Karnataka", "Bangalore", "warp-drive", 2, null, 13L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 3, null, 14L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 1, null, 15L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "force-field", 90, null, 16L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 48, null, 17L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 4800, null, 19L }); list.add(new Object[] { "US", "California", "San Jose", "warp-drive", 90000, null, 20L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 4800, null, 21L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 4800, null, 22L }); list.add(new Object[] { "India", "Karnataka", "Bangalore", "warp-drive", 10, null, 23L }); list.add(new Object[] { "US", "California", "San Jose", "force-field", 1200, null, 24L }); return list; } @Override protected int getMaxDataRows() { return data.size(); } @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.Integer.class.getName(), java.sql.Timestamp.class.getName(), java.lang.Long.class.getName() }; } 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(TimeWFPartitionWinSizeProviderTest.this .getEventTimeStamp(counter)); System.out.println(Arrays.asList(event)); counter++; return event; } /** * @throws UnsupportedOperationException */ public void remove() { throw new UnsupportedOperationException(); } }; return iter; } @Override protected void beforeQueryParse() { super.beforeQueryParse(); try { cruncher.registerProvider("TimeWindowSize/Mine", CustomWindowSizeProvider.class); } catch (StreamCruncherException e) { throw new RuntimeException(e); } } @Override protected String getRQL() { String csv = getRQLColumnsCSV(); return "select " + csv + " from test (partition by item_sku store last " + windowSize + " seconds max " + windowSize + " 'TimeWindowSize/Mine') as testStr" + " where testStr.$row_status is not dead;"; } @Override protected void verify(List<BatchResult> results) { HashSet<Long> orderIds = new HashSet<Long>(); 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(); Map<String, SortedSet<Long>> partitionedData = new HashMap<String, SortedSet<Long>>(); System.out.println(" Batch results"); for (Object[] objects : rows) { System.out.print(" "); for (Object object : objects) { System.out.print(object + " "); } /* * "country", "state", "city", "item_sku", "item_qty", * "order_time", "order_id" */ SortedSet<Long> itemSKUWindow = partitionedData.get(objects[3]); if (itemSKUWindow == null) { itemSKUWindow = new TreeSet<Long>(); partitionedData.put((String) objects[3], itemSKUWindow); } itemSKUWindow.add((Long) objects[6]); if (orderIds.contains(objects[6]) == false) { System.out.print(" (Adding/Sliding in)"); orderIds.add((Long) objects[6]); } System.out.println(); } int currBatchCount = 0; for (String itemSKU : partitionedData.keySet()) { SortedSet<Long> set = partitionedData.get(itemSKU); currBatchCount = currBatchCount + set.size(); int expectedSize = itemSKU.equals("force-field") ? 20 : windowSize; Assert.assertTrue((set.size() <= expectedSize), "Set: " + set + " size is greater than expected Window-size of: " + expectedSize); } Assert.assertEquals(currBatchCount, result.getRows().size(), "Batch content does not match expected number of Rows."); } Assert.assertEquals(orderIds.size(), getMaxDataRows(), "Expected rows received don't match the number of inserted rows."); } // ------------ public static class CustomWindowSizeProvider extends TimeWindowSizeProvider { /** * @param levelValues * Will be item_sku value. */ @Override public long provideSizeMillis(Object[] levelValues) { if (levelValues[0].equals("force-field")) { // 50 second Window. return 50 * 1000; } // Default for the others. return super.provideSizeMillis(levelValues); } /** * @param levelValues * Will be item_sku value. */ @Override public int provideSize(Object[] levelValues) { if (levelValues[0].equals("force-field")) { // 20 size Window. return 20; } // Default for the others. return super.provideSize(levelValues); } } }