SlideShare a Scribd company logo
In memory OLAP engine
Samuel Pelletier	

Kaviju inc.	

samuel@kaviju.com
OLAP ?
• An acronym for OnLine Analytical Processing.	

• In simple words, a system to query a multidimensional data set
and get answer fast for interactive reports. 	

• A well known implementation is an Excel Pivot Table.
Why build something new
• I wanted something fast, memory efficient for simple queries with
millions of facts. 	

• Sql queries dost not works for millions of facts with multiple
dimensions, especially with large number of rows.	

• There are specialized tools for OLAP from Microsoft, Oracle and
others but they are large and expensive, too much for my needs.	

• Generic cheap toolkits are not memory efficient, this is the cost for
their simplicity.	

• I wanted a simple solution to deploy with minimal dependency.
Memory usage and time to
retrieve 1 000 000 invoice lines
• Fetching EOs uses 1.2 GB of ram in 13-19 s	

• Fetching raw rows uses 750 MB of ram in 5-8 s.	

• Fetching as POJOs with jdbc uses 130 MB in 4.0 s.	

• Reading from file as POJOs uses 130 MB in 1.4 s.	

• For 7 M rows, EOs would require 8.4 GB for gazillions of small
objects (bad for the GC).
Time to compute sum of sales for
1 000 000 invoice lines
• 2.1 s for "select sum(sales)..." in FrontBase with table in RAM.	

• 0.5 s for @sum.sales on EOs.	

• 0.12 s for @sum.sales on raw rows.	

• 0.5 s for @sum.sales on POJOs.	

• 0.009 s for a loop with direct attribute access on POJOs.
Some concepts
• Facts are the elements being analyzed.An exemple is invoice
lines.	

• Facts contains measures like quantities, prices or amounts.	

• Facts are linked to dimensions used to filter and aggregate
them. For invoice lines, we have product, invoice, date, etc.	

• Dimensions are often part of a hierarchy, for example, products
are in a product category, dates are in a month and in a week.
Sample Invoice dimension hierarchy
Invoice
Line
Invoice
Date
Month
Ship to Client type
Sold to
Product
Salesman
SalesManager
Week
Client type
Measures:
Shipped Qty
Sales
Profits
Steps to implement an engine
• Create the Engine class.	

• Create required classes to model the dimension hierarchy. 	

• Create theValue class for your facts.	

• Create the Group class that will compute summarized results.	

• Create the dimensions definition classes.
Engine class
• Engine class extends OlapEngine with Group andValue types.

	

	

 public class SalesEngine extends OlapEngine<GroupEntry,Value>	

• Create the objects required for the data model and lookup table
used to load the facts.	

• Load the fact intoValue objects.	

• Create and register the dimensions.
Create required model objects
public class Product {	
	 public final int code;	
	 public final String name;	
	 public final ProductCategory category;	
	 	
	 public Product(int code, String name, ProductCategory category) {	
	 	 super();	
	 	 this.code = code;	
	 	 this.name = name;	
	 	 this.category = category;	
	 }	
}	
!
	 private void loadProducts() {	
	 	 productsByCode = new HashMap<Integer, Product>();	
!
	 	 WOResourceManager resourceManager = ERXApplication.application().resourceManager();	
	 	 String fileName = "olapData/products.txt";	
	 	 try ( InputStream fileData = resourceManager.inputStreamForResourceNamed(fileName, null, null);) {	
	 	 	 InputStreamReader fileReader = new InputStreamReader(fileData, "utf-8");	
	 	 	 BufferedReader reader = new BufferedReader(fileReader);	
	 	 	 String line;	
	 	 	 while ( (line = reader.readLine()) != null) {	
	 	 	 	 String[] cols = line.split("t", -1);	
	 	 	 	 Product product = new Product(Integer.parseInt(cols[0]), cols[0], categoryWithID(cols[1]));	
	 	 	 	 	
	 	 	 	 productsByCode.put(product.code, product);	
	 	 	 }	
	 	 }	
	 	 ...	
	 }
Load the facts and create dimensions
	 private void loadInvoiceLines() {	
	 	 ...	
	 	 loadProductCategories();	
	 	 loadProducts();	
!
	 	 InvoiceDimension invoiceDim = new InvoiceDimension(this);	
	 	 SalesmanDimension salesmanDim = new SalesmanDimension(this);	
	 	 	 while ( (line = reader.readLine()) != null) {	
	 	 	 	 String[] cols = line.split("t", -1);	
!
	 	 	 	 InvoiceLine invoiceLine = new InvoiceLine(valueIndex++, Short.parseShort(cols[1]));	
	 	 	 	 invoiceLine.shippedQty = Integer.parseInt(cols[6]);	
	 	 	 	 invoiceLine.sales = Float.parseFloat(cols[7]);	
	 	 	 	 invoiceLine.profits = Float.parseFloat(cols[8]);	
	 	 	 	 lines.add(invoiceLine);	
	 	 	 	 	
	 	 	 	 invoiceDim.addLine(invoiceLine, cols[0], cols);	
!
	 	 	 	 invoiceLine.salesmanNumber = Integer.parseInt(cols[12]);	
	 	 	 	 salesmanDim.addIndexEntry(invoiceLine.salesmanNumber, invoiceLine);	
	 	 	 	 ...	
	 	 	 }	
	 	 }	
	 	 addDimension(productDimension);	
	 	 addDimension(productDimension.createProductCategoryDimension());	
	 	 ...	
	 	 lines.trimToSize();	
	 	 setValues(lines);	
	 }
Value and GroupEntry classes
• Value classe contains your basic facts (invoice lines for example) 

	

	

 public class InvoiceLine extends OlapValue<Sales>	

• GroupEntry is use to compute summarized results.

	

	

 public class Sales extends GroupEntry<InvoiceLine>	

• These are tightly coupled, a GroupEntry represent a computed
result for an array ofValues; metrics are found in both classes.
Value Class
public class InvoiceLine extends OlapValue<Sales> {	
	 public Invoice invoice;	
	 public final short lineNumber;	
	 	
	 public Product product;	
!
	 public int shippedQty;	
	 public float sales;	
	 public float profits;	
!
	 public int salesmanNumber;	
	 public int salesManagerNumber;	
!
	 public InvoiceLine(int valueIndex, short lineNumber) {	
	 	 super(valueIndex);	
	 	 this.lineNumber = lineNumber;	
	 }	
}
GroupEntry class
public class Sales extends GroupEntry<InvoiceLine> {	
	 private int shippedQty;	
	 private double sales = 0.0;	
	 private double profits = 0.0;	
	 	
!
	 public Sales(GroupEntryKey<Sales, InvoiceLine> key) {	
	 	 super(key);	
	 }	
!
	 @Override	
	 public void addEntry(InvoiceLine entry) {	
	 	 shippedQty += entry.shippedQty;	
	 	 sales += entry.sales;	
	 	 profits += entry.profits;	
	 }	
!
	 @Override	
	 public void optimizeMemoryUsage() {	
	 }	
	 	 return sales;	
	 }	
!
	 ...	
}
Dimensions classes
• Dimensions implement the engine indexes and key extraction for
result aggregation.	

• Dimensions are usually linked to another class representing an
entity like Invoice, Client, Product or ProductCatogory.	

• Entity are value object POJO for optimal speed an memory
usage.You may add a method to get the corresponding eo.	

• Dimensions are either leaf (a group of facts) or group (a group of
leaf entries).
Product dimension class
public class ProductDimension extends OlapLeafDimension<Sales,Integer,InvoiceLine> {	
!
	 public ProductDimension(OlapEngine<Sales, InvoiceLine> engine) {	
	 	 super(engine, "productCode");	
	 }	
!
	 @Override	
	 public Integer getKeyForEntry(InvoiceLine entry) {	
	 	 return entry.product.code;	
	 }	
!
	 @Override	
	 public Integer getKeyForString(String keyString) {	
	 	 return Integer.valueOf(keyString);	
	 }	
	 	
	 public ProductCategoryDimension createProductCategoryDimension() {	
	 	 long startTime = System.currentTimeMillis();	
	 	 ProductCategoryDimension dimension = new ProductCategoryDimension(engine, this);	
!
	 	 for (Product product : salesEngine().products()) {	
	 	 	 dimension.addIndexEntry(product.category.categoryID, product.code);	
	 	 }	
	 	 long fetchTime = System.currentTimeMillis() - startTime;	
	 	 engine.logMessage("createProductCategoryDimension completed in "+fetchTime+"ms.");	
	 	 return dimension;	
	 }	
!
	 private SalesEngine salesEngine() {	
	 	 return (SalesEngine) engine;	
	 }
Product category dimension class
public class ProductCategoryDimension extends OlapGroupDimension<Sales,Integer,InvoiceLine,ProductDimension,Integer> {	
!
	 public ProductCategoryDimension(OlapEngine<Sales, InvoiceLine> engine, ProductDimension childDimension) {	
	 	 super(engine, "productCategoryCode", childDimension);	
	 }	
!
	 @Override	
	 public Integer getKeyForEntry(InvoiceLine entry) {	
	 	 return entry.product.category.categoryID;	
	 }	
!
	 @Override	
	 public Integer getKeyForString(String keyString) {	
	 	 return Integer.valueOf(keyString);	
	 }
Initialize and use in an app
• The engine is multithread capable once loaded.	

• I usually create a singleton for the engine; it can also be in your
app class.	

• Entity are value object POJO for optimal speed an memory
usage.You may add a method to get the corresponding eo.	

• Dimensions are either leaf (a group of facts) or group (a group of
leaf entries).
Use in a application
	 public Application() {	
	 	 ...	
	 	 SalesEngine.createEngine();	
	 }	
!
!
In the component that uses the engine	
!
	 public OlapNavigator(WOContext context) {	
	 	 super(context);	
	 	 ....	
	 	 engine = SalesEngine.sharedEngine();	
	 	 if (engine == null) {	
	 	 	 Engine me bay null if it has not completed it's loading...	
	 	 }	
	 }	
!
	 someFetchMethod() {	
	 	 OlapResult<Sales, InvoiceLine> result = engine.resultForRequest(query);	
!
	 	 rows = new NSArray<Sales>(result.getGroups());	
	 	 	
	 	 sort or put inside a ERXDisplayGroup...	
	 }	
!
Demo app
Java and memory
• To keep the garbage collector happy, it is better to have a
maximum heap at least 2-3 times the real usage.	

• GC can kill your app performance if memory is starved.With
default setting, it may even kill your server by using multiple core
for long periods at least in 1.5 and 1.6.	

• Java 1.7 contains a new collector, probable better.
Q&A
Samuel Pelletier	

samuel@kaviju.com

More Related Content

PDF
KAAccessControl
PDF
D2W Stateful Controllers
PDF
Life outside WO
PDF
Unit Testing with WOUnit
PPTX
Real World MVC
PDF
[2015/2016] Local data storage for web-based mobile apps
PDF
Lecture 9 - Java Persistence, JPA 2
PPTX
Евгений Капинос "Advanced JPA (Java Persistent API)"
KAAccessControl
D2W Stateful Controllers
Life outside WO
Unit Testing with WOUnit
Real World MVC
[2015/2016] Local data storage for web-based mobile apps
Lecture 9 - Java Persistence, JPA 2
Евгений Капинос "Advanced JPA (Java Persistent API)"

What's hot (20)

PDF
Drupal8 for Symfony Developers (PHP Day Verona 2017)
PPTX
Advance java session 11
PPTX
MVC & SQL_In_1_Hour
PDF
JavaScript - Chapter 12 - Document Object Model
PDF
Lecture 4: JavaServer Pages (JSP) & Expression Language (EL)
PDF
Lecture 3: Servlets - Session Management
PDF
Apex Code Analysis Using the Tooling API and Canvas
PPTX
PPT
ExtJs Basic Part-1
PPTX
Hibernate
PDF
Hibernate Presentation
PDF
Sling Models Using Sightly and JSP by Deepak Khetawat
PPTX
Using the Tooling API to Generate Apex SOAP Web Service Clients
PPTX
JavaOne 2014 - CON2013 - Code Generation in the Java Compiler: Annotation Pro...
PDF
PDF
C# Advanced L07-Design Patterns
PDF
Michael Bayer Introduction to SQLAlchemy @ Postgres Open
PDF
Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions
PDF
DataFX - JavaOne 2013
PDF
Efficient Rails Test Driven Development (class 3) by Wolfram Arnold
Drupal8 for Symfony Developers (PHP Day Verona 2017)
Advance java session 11
MVC & SQL_In_1_Hour
JavaScript - Chapter 12 - Document Object Model
Lecture 4: JavaServer Pages (JSP) & Expression Language (EL)
Lecture 3: Servlets - Session Management
Apex Code Analysis Using the Tooling API and Canvas
ExtJs Basic Part-1
Hibernate
Hibernate Presentation
Sling Models Using Sightly and JSP by Deepak Khetawat
Using the Tooling API to Generate Apex SOAP Web Service Clients
JavaOne 2014 - CON2013 - Code Generation in the Java Compiler: Annotation Pro...
C# Advanced L07-Design Patterns
Michael Bayer Introduction to SQLAlchemy @ Postgres Open
Connect.Tech- Enhancing Your Workflow With Xcode Source Editor Extensions
DataFX - JavaOne 2013
Efficient Rails Test Driven Development (class 3) by Wolfram Arnold
Ad

Viewers also liked (17)

PDF
ERRest in Depth
PDF
ERRest
PDF
ERRest - The Next Steps
PDF
Migrating existing Projects to Wonder
PDF
Reenabling SOAP using ERJaxWS
PDF
Chaining the Beast - Testing Wonder Applications in the Real World
PDF
iOS for ERREST - alternative version
PDF
Using Nagios to monitor your WO systems
PDF
PDF
iOS for ERREST
PDF
Build and deployment
PDF
Apache Cayenne for WO Devs
PDF
Filtering data with D2W
PDF
Advanced Apache Cayenne
PDF
Deploying WO on Windows
PDF
High availability
PDF
"Framework Principal" pattern
ERRest in Depth
ERRest
ERRest - The Next Steps
Migrating existing Projects to Wonder
Reenabling SOAP using ERJaxWS
Chaining the Beast - Testing Wonder Applications in the Real World
iOS for ERREST - alternative version
Using Nagios to monitor your WO systems
iOS for ERREST
Build and deployment
Apache Cayenne for WO Devs
Filtering data with D2W
Advanced Apache Cayenne
Deploying WO on Windows
High availability
"Framework Principal" pattern
Ad

Similar to In memory OLAP engine (20)

PPTX
Map Reduce: Which Way To Go?
PPT
Bw training 1 intro dw
DOCX
VISUALIZAR REGISTROS EN UN JTABLE
PDF
Business Intelligence: OLAP, Data Warehouse, and Column Store
PPTX
Knowage manual
PPT
DWO -Pertemuan 1
PPT
OLAP Cubes in Datawarehousing
PPT
Data ware housing- Introduction to olap .
DOC
Dwh faqs
PDF
Big Data in Memory - SpringOne 2014
PPTX
In memory databases presentation
PDF
The olap tutorial 2012
PDF
Data warehousing unit 6.2
PPTX
INTRODUCTION TO ONLINE ALYTICAL PROCESS WITH FEATURES AND OPERATIONS
PDF
OO_ABAP_BASIC_CONCEPTS_1741540582ete.pdf
PPT
Introduction To Msbi By Yasir
PDF
2 olap operaciones
PPTX
PPTX
Project report aditi paul1
PPTX
Oracle Hyperion overview
Map Reduce: Which Way To Go?
Bw training 1 intro dw
VISUALIZAR REGISTROS EN UN JTABLE
Business Intelligence: OLAP, Data Warehouse, and Column Store
Knowage manual
DWO -Pertemuan 1
OLAP Cubes in Datawarehousing
Data ware housing- Introduction to olap .
Dwh faqs
Big Data in Memory - SpringOne 2014
In memory databases presentation
The olap tutorial 2012
Data warehousing unit 6.2
INTRODUCTION TO ONLINE ALYTICAL PROCESS WITH FEATURES AND OPERATIONS
OO_ABAP_BASIC_CONCEPTS_1741540582ete.pdf
Introduction To Msbi By Yasir
2 olap operaciones
Project report aditi paul1
Oracle Hyperion overview

More from WO Community (12)

PDF
Localizing your apps for multibyte languages
PDF
PDF
ERGroupware
PDF
D2W Branding Using jQuery ThemeRoller
PDF
CMS / BLOG and SnoWOman
PDF
Using GIT
PDF
Persistent Session Storage
PDF
Back2 future
PDF
WebObjects Optimization
PDF
Dynamic Elements
PDF
Practical ERSync
PDF
ERRest: the Basics
Localizing your apps for multibyte languages
ERGroupware
D2W Branding Using jQuery ThemeRoller
CMS / BLOG and SnoWOman
Using GIT
Persistent Session Storage
Back2 future
WebObjects Optimization
Dynamic Elements
Practical ERSync
ERRest: the Basics

Recently uploaded (20)

PDF
GDG Cloud Iasi [PUBLIC] Florian Blaga - Unveiling the Evolution of Cybersecur...
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
cuic standard and advanced reporting.pdf
PDF
Advanced IT Governance
PDF
GamePlan Trading System Review: Professional Trader's Honest Take
PDF
Approach and Philosophy of On baking technology
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Empathic Computing: Creating Shared Understanding
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
[발표본] 너의 과제는 클라우드에 있어_KTDS_김동현_20250524.pdf
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Modernizing your data center with Dell and AMD
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
NewMind AI Monthly Chronicles - July 2025
GDG Cloud Iasi [PUBLIC] Florian Blaga - Unveiling the Evolution of Cybersecur...
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
cuic standard and advanced reporting.pdf
Advanced IT Governance
GamePlan Trading System Review: Professional Trader's Honest Take
Approach and Philosophy of On baking technology
Mobile App Security Testing_ A Comprehensive Guide.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Empathic Computing: Creating Shared Understanding
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
[발표본] 너의 과제는 클라우드에 있어_KTDS_김동현_20250524.pdf
Chapter 3 Spatial Domain Image Processing.pdf
Understanding_Digital_Forensics_Presentation.pptx
Modernizing your data center with Dell and AMD
Diabetes mellitus diagnosis method based random forest with bat algorithm
The AUB Centre for AI in Media Proposal.docx
Spectral efficient network and resource selection model in 5G networks
The Rise and Fall of 3GPP – Time for a Sabbatical?
NewMind AI Monthly Chronicles - July 2025

In memory OLAP engine

  • 1. In memory OLAP engine Samuel Pelletier Kaviju inc. samuel@kaviju.com
  • 2. OLAP ? • An acronym for OnLine Analytical Processing. • In simple words, a system to query a multidimensional data set and get answer fast for interactive reports. • A well known implementation is an Excel Pivot Table.
  • 3. Why build something new • I wanted something fast, memory efficient for simple queries with millions of facts. • Sql queries dost not works for millions of facts with multiple dimensions, especially with large number of rows. • There are specialized tools for OLAP from Microsoft, Oracle and others but they are large and expensive, too much for my needs. • Generic cheap toolkits are not memory efficient, this is the cost for their simplicity. • I wanted a simple solution to deploy with minimal dependency.
  • 4. Memory usage and time to retrieve 1 000 000 invoice lines • Fetching EOs uses 1.2 GB of ram in 13-19 s • Fetching raw rows uses 750 MB of ram in 5-8 s. • Fetching as POJOs with jdbc uses 130 MB in 4.0 s. • Reading from file as POJOs uses 130 MB in 1.4 s. • For 7 M rows, EOs would require 8.4 GB for gazillions of small objects (bad for the GC).
  • 5. Time to compute sum of sales for 1 000 000 invoice lines • 2.1 s for "select sum(sales)..." in FrontBase with table in RAM. • 0.5 s for @sum.sales on EOs. • 0.12 s for @sum.sales on raw rows. • 0.5 s for @sum.sales on POJOs. • 0.009 s for a loop with direct attribute access on POJOs.
  • 6. Some concepts • Facts are the elements being analyzed.An exemple is invoice lines. • Facts contains measures like quantities, prices or amounts. • Facts are linked to dimensions used to filter and aggregate them. For invoice lines, we have product, invoice, date, etc. • Dimensions are often part of a hierarchy, for example, products are in a product category, dates are in a month and in a week.
  • 7. Sample Invoice dimension hierarchy Invoice Line Invoice Date Month Ship to Client type Sold to Product Salesman SalesManager Week Client type Measures: Shipped Qty Sales Profits
  • 8. Steps to implement an engine • Create the Engine class. • Create required classes to model the dimension hierarchy. • Create theValue class for your facts. • Create the Group class that will compute summarized results. • Create the dimensions definition classes.
  • 9. Engine class • Engine class extends OlapEngine with Group andValue types.
 public class SalesEngine extends OlapEngine<GroupEntry,Value> • Create the objects required for the data model and lookup table used to load the facts. • Load the fact intoValue objects. • Create and register the dimensions.
  • 10. Create required model objects public class Product { public final int code; public final String name; public final ProductCategory category; public Product(int code, String name, ProductCategory category) { super(); this.code = code; this.name = name; this.category = category; } } ! private void loadProducts() { productsByCode = new HashMap<Integer, Product>(); ! WOResourceManager resourceManager = ERXApplication.application().resourceManager(); String fileName = "olapData/products.txt"; try ( InputStream fileData = resourceManager.inputStreamForResourceNamed(fileName, null, null);) { InputStreamReader fileReader = new InputStreamReader(fileData, "utf-8"); BufferedReader reader = new BufferedReader(fileReader); String line; while ( (line = reader.readLine()) != null) { String[] cols = line.split("t", -1); Product product = new Product(Integer.parseInt(cols[0]), cols[0], categoryWithID(cols[1])); productsByCode.put(product.code, product); } } ... }
  • 11. Load the facts and create dimensions private void loadInvoiceLines() { ... loadProductCategories(); loadProducts(); ! InvoiceDimension invoiceDim = new InvoiceDimension(this); SalesmanDimension salesmanDim = new SalesmanDimension(this); while ( (line = reader.readLine()) != null) { String[] cols = line.split("t", -1); ! InvoiceLine invoiceLine = new InvoiceLine(valueIndex++, Short.parseShort(cols[1])); invoiceLine.shippedQty = Integer.parseInt(cols[6]); invoiceLine.sales = Float.parseFloat(cols[7]); invoiceLine.profits = Float.parseFloat(cols[8]); lines.add(invoiceLine); invoiceDim.addLine(invoiceLine, cols[0], cols); ! invoiceLine.salesmanNumber = Integer.parseInt(cols[12]); salesmanDim.addIndexEntry(invoiceLine.salesmanNumber, invoiceLine); ... } } addDimension(productDimension); addDimension(productDimension.createProductCategoryDimension()); ... lines.trimToSize(); setValues(lines); }
  • 12. Value and GroupEntry classes • Value classe contains your basic facts (invoice lines for example) 
 public class InvoiceLine extends OlapValue<Sales> • GroupEntry is use to compute summarized results.
 public class Sales extends GroupEntry<InvoiceLine> • These are tightly coupled, a GroupEntry represent a computed result for an array ofValues; metrics are found in both classes.
  • 13. Value Class public class InvoiceLine extends OlapValue<Sales> { public Invoice invoice; public final short lineNumber; public Product product; ! public int shippedQty; public float sales; public float profits; ! public int salesmanNumber; public int salesManagerNumber; ! public InvoiceLine(int valueIndex, short lineNumber) { super(valueIndex); this.lineNumber = lineNumber; } }
  • 14. GroupEntry class public class Sales extends GroupEntry<InvoiceLine> { private int shippedQty; private double sales = 0.0; private double profits = 0.0; ! public Sales(GroupEntryKey<Sales, InvoiceLine> key) { super(key); } ! @Override public void addEntry(InvoiceLine entry) { shippedQty += entry.shippedQty; sales += entry.sales; profits += entry.profits; } ! @Override public void optimizeMemoryUsage() { } return sales; } ! ... }
  • 15. Dimensions classes • Dimensions implement the engine indexes and key extraction for result aggregation. • Dimensions are usually linked to another class representing an entity like Invoice, Client, Product or ProductCatogory. • Entity are value object POJO for optimal speed an memory usage.You may add a method to get the corresponding eo. • Dimensions are either leaf (a group of facts) or group (a group of leaf entries).
  • 16. Product dimension class public class ProductDimension extends OlapLeafDimension<Sales,Integer,InvoiceLine> { ! public ProductDimension(OlapEngine<Sales, InvoiceLine> engine) { super(engine, "productCode"); } ! @Override public Integer getKeyForEntry(InvoiceLine entry) { return entry.product.code; } ! @Override public Integer getKeyForString(String keyString) { return Integer.valueOf(keyString); } public ProductCategoryDimension createProductCategoryDimension() { long startTime = System.currentTimeMillis(); ProductCategoryDimension dimension = new ProductCategoryDimension(engine, this); ! for (Product product : salesEngine().products()) { dimension.addIndexEntry(product.category.categoryID, product.code); } long fetchTime = System.currentTimeMillis() - startTime; engine.logMessage("createProductCategoryDimension completed in "+fetchTime+"ms."); return dimension; } ! private SalesEngine salesEngine() { return (SalesEngine) engine; }
  • 17. Product category dimension class public class ProductCategoryDimension extends OlapGroupDimension<Sales,Integer,InvoiceLine,ProductDimension,Integer> { ! public ProductCategoryDimension(OlapEngine<Sales, InvoiceLine> engine, ProductDimension childDimension) { super(engine, "productCategoryCode", childDimension); } ! @Override public Integer getKeyForEntry(InvoiceLine entry) { return entry.product.category.categoryID; } ! @Override public Integer getKeyForString(String keyString) { return Integer.valueOf(keyString); }
  • 18. Initialize and use in an app • The engine is multithread capable once loaded. • I usually create a singleton for the engine; it can also be in your app class. • Entity are value object POJO for optimal speed an memory usage.You may add a method to get the corresponding eo. • Dimensions are either leaf (a group of facts) or group (a group of leaf entries).
  • 19. Use in a application public Application() { ... SalesEngine.createEngine(); } ! ! In the component that uses the engine ! public OlapNavigator(WOContext context) { super(context); .... engine = SalesEngine.sharedEngine(); if (engine == null) { Engine me bay null if it has not completed it's loading... } } ! someFetchMethod() { OlapResult<Sales, InvoiceLine> result = engine.resultForRequest(query); ! rows = new NSArray<Sales>(result.getGroups()); sort or put inside a ERXDisplayGroup... } !
  • 21. Java and memory • To keep the garbage collector happy, it is better to have a maximum heap at least 2-3 times the real usage. • GC can kill your app performance if memory is starved.With default setting, it may even kill your server by using multiple core for long periods at least in 1.5 and 1.6. • Java 1.7 contains a new collector, probable better.