SlideShare a Scribd company logo
1 of 36
Download to read offline
Improving Performance and Flexibility
of Content Listings Using Criteria API
Nils Breunese
Public Broadcaster since 1926 The Netherlands
Online since 1994 Open-source CMS released in 1997
Using Magnolia since 2010 Still migrating websites
Tens of thousands of pages Multiple sites like that
Overview pages Lots of them
Thanks for the warning… Even 10 seconds would be way too long
WARN info.magnolia.module.cache.filter.CacheFilter
-- The following URL took longer than 10 seconds
(63969 ms) to render. This might cause timeout
exceptions on other requests to the same URI.
Overview models Standard Templating Kit
Tracking back from the template newsOverview.ftl
(...)
[#assign pager = model.pager]

[#assign newsList = cmsfn.asContentMapList(pager.pageItems)!]
(...)
Constructing the pager AbstractItemListModel
public STKPager getPager() throws RepositoryException {

(...)

return new STKPager(currentPageLink, getItems(), content);

}
Four step pipeline AbstractItemListModel
public Collection<Node> getItems() throws RepositoryException {

List<Node> itemsList = search();



this.filter(itemsList);

this.sort(itemsList);

itemsList = this.shrink(itemsList);



return itemsList;

}
1
2
3
4
Step 1a: Constructing the query TemplateCategoryUtil
public static List<Node> getContentListByTemplateNames(...) {
(...)
StringBuffer sql = new StringBuffer(
"select * from nt:base where jcr:path like '"
+ path + "/%'");
(...add 'mgnl:template=' clauses...)
(...add 'ORDER BY' clauses...)

return getWrappedNodesFromQuery(sql.toString(),
repository, maxResultSize);
} maxResultSize == Integer.MAX_VALUE
Step 1b: Executing the query TemplateCategoryUtil
public static List<Node> getContentListByTemplateNames(...) {
(...)

NodeIterator items = QueryUtil.search(
repository,
sql.toString(),
Query.SQL,
NodeTypes.Content.NAME);
}
Step 2: Filtering the item list STKDateContentUtil
public static void filterDateContentList(...) {

CollectionUtils.filter(itemsList, new Predicate() {

@Override

public boolean evaluate(Object object) {

(...)
return date.after(minDate) && date.before(maxDate);

}

});

}
Step 3: Time to sort STKDateContentUtil
public static void sortDateContentList(...) {

Collections.sort(itemsList, new Comparator<Node>() {

@Override

public int compare(Node c1, Node c2) {

(...)

if (StringUtils.equals(sortDirection, ASCENDING)) {

return date2.compareTo(date1);

}

return date1.compareTo(date2);

}

});

}
Step 4: Shrinking the list STKTemplatingFunctions
public List<Node> cutList(List<Node> itemsList, final int maxResults) {

if (itemsList.size() > maxResults) {

return itemsList.subList(0, maxResults);

}

return itemsList;

}
NewsOverviewModel passes Integer.MAX_VALUE,
so shrink does effectively nothing in this case
Step 5: Get the items from the pager STKPager
public Collection getPageItems() {



Collection subList = items;

int offset = getOffset();

if (count > 0) {

int limit = maxResultsPerPage + offset;

if (items.size() < limit) {

limit = count;

}

subList = ((List) items).subList(offset, limit);



}

return subList;

}
maxResultsPerPage is
typically something like 20
When this becomes a problem We have multiple sites like this
select * from nt:base
where jcr:path like '/siteX/news/%' AND
mgnl:template = 'standard-templating-kit:pages/stkNews'
20000 pages under website:/siteX/news
Four step pipeline returns STKPager with 20000 items (page nodes)
[#assign model.pager]
[#assign newsList = cmsfn.asContentMapList(pager.pageItems)!]
STKPager returns list with 20 page nodes
19980 Node objects created, but not rendered
A query could do all steps at once JCR queries are pretty flexible
Everything in a single JCR query Only 20 nodes returned
SELECT * FROM nt:base
WHERE jcr:path LIKE '/siteX/news/%' AND
mgnl:template = 'standard-templating-kit:pages/stkNews'
AND jcr:created < cast('2016-06-07T00:00:00.000Z' AS DATE)
ORDER BY date ASCENDING
LIMIT 20 OFFSET 20
Search
Filter
Sort
Paging
Criteria API For those familiar with Hibernate/JPA
Criteria criteria = JCRCriteriaFactory.createCriteria()

.setBasePath("/siteX/news")

.add(Restrictions.eq(
"@mgnl:template", "standard-templating-kit:pages/stkNews"))

.add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))

.addOrder(Order.asc("date"))

.setPaging(20, 1);


ResultIterator<...> items = criteria.execute(session).getItems();
Sort
Paging
Filter
Search
Criteria API for Magnolia CMS Magnolia module by Openmind
jcr-criteria https://github.com/vpro/jcr-criteria
Custom pager Only a single page worth of items
public class VtkPager<T> extends STKPager {


private final List<? extends T> items;
private final int pageSize;

private final int count;



(...)



@Override

public List<? extends T> getPageItems() {

return items;

}
}
Use it in your model classes VtkContentListModel (vpro)
public abstract class VtkContentListModel ... {



protected final VtkPager<ContentMap> pager;



@Override

public String execute() {

pager = createPager();

return super.execute();

}



protected abstract VtkPager<T> createPager();
(...)
}
Concrete Example VtkNewsOverviewModel (vpro)
@Override

protected VtkPager<Node> createPager() {
(...)

AdvancedResult result = JCRCriteriaFactory.createCriteria()

.setBasePath(path)

.add(Restrictions.in("@mgnl:template", templates))

.add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))
.addOrder(Order.asc("date"))
.setPaging(itemsPerPage, pageNumberStartingFromOne)
.execute(session);

List<Node> items = new ArrayList<>();

for (AdvancedResultItem item : result.getItems()) {

items.add(item.getJCRNode());

}



int count = result.getTotalSize();



return new VtkPager<>(link, items, content, itemsPerPage, count);
}
Still this. Was it all for nothing? :o(
WARN info.magnolia.module.cache.filter.CacheFilter
-- The following URL took longer than 10 seconds
(63969 ms) to render. This might cause timeout
exceptions on other requests to the same URI.
Example VtkNewsOverviewModel (vpro)
@Override

protected VtkPager<Node> createPager() {
(...)

AdvancedResult result = JCRCriteriaFactory.createCriteria()

.setBasePath(path)

.add(Restrictions.in("@mgnl:template", templates))

.add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))
.addOrder(Order.asc("date"))
.setPaging(itemsPerPage, pageNumberStartingFromOne)
.execute(session);

List<Node> items = new ArrayList<>();

for (AdvancedResultItem item : result.getItems()) {

items.add(item.getJCRNode());

}



int count = result.getTotalSize();



return new VtkPager<>(link, items, content, itemsPerPage, count);
}
This call takes 10-60+ seconds!
AdvancedResultImpl (jcr-criteria)
@Override

public int getTotalSize() {

if (totalResults == null) {

int queryTotalSize = -1;

try { // jcrQueryResult instanceof JackrabbitQueryResult) {

Method m = jcrQueryResult.getClass().getMethod("getTotalSize");

queryTotalSize = (int) m.invoke(jcrQueryResult);

} catch (InvocationTargetException | IllegalAccessException e) {

LOG.error(e.getMessage(), e);

} catch (NoSuchMethodException e) {



}

if (queryTotalSize == -1 && (itemsPerPage == 0 || applyLocalPaging)) {

try {

totalResults = (int) jcrQueryResult.getNodes().getSize();

} catch (RepositoryException e) {

// ignore, the standard total size will be returned

}

}



if (queryTotalSize == -1) {

totalResults = queryCounter.getAsInt();

} else {

totalResults = queryTotalSize;



}

}

return totalResults;

}
We end up here
jackrabbit-core 2.8.0
protected void getResults(long size) throws RepositoryException {

(...)

result = executeQuery(maxResultSize); // Lucene query
(...)
// Doesn’t use result.getSize(), call collectScoreNodes(...)
}
private void collectScoreNodes(...) {

while (collector.size() < maxResults) {

ScoreNode[] sn = hits.nextScoreNodes();
(...)

// check access

if (isAccessGranted(sn)) {

collector.add(sn);

} else {

invalid++;

}

}

} QueryResultImpl
It used to be fast! https://issues.apache.org/jira/browse/JCR-3858
jackrabbit-core 2.10.0+
protected void getResults(long size) throws RepositoryException {
(...)
if (sizeEstimate) {

numResults = result.getSize(); // Use count from Lucene



} else {

// do things the Jackrabbit 2.8.0 way

(...)

}
(...)
}
QueryResultImpl
Enable Jackrabbit’s 'sizeEstimate' Jackrabbit 2.10+
<SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
(...)
<param name="sizeEstimate" value="true"/>
</SearchIndex>
Rendering times down to 1-2 seconds Bingo
Time for questions
Anyone?
Feel free to contact me
Nils Breunese

@breun

n.breunese@vpro.nl

More Related Content

What's hot

MongoDB Chunks - Distribution, Splitting, and Merging
MongoDB Chunks - Distribution, Splitting, and MergingMongoDB Chunks - Distribution, Splitting, and Merging
MongoDB Chunks - Distribution, Splitting, and MergingJason Terpko
 
Google cloud datastore driver for Google Apps Script DB abstraction
Google cloud datastore driver for Google Apps Script DB abstractionGoogle cloud datastore driver for Google Apps Script DB abstraction
Google cloud datastore driver for Google Apps Script DB abstractionBruce McPherson
 
Lab1-DB-Cassandra
Lab1-DB-CassandraLab1-DB-Cassandra
Lab1-DB-CassandraLilia Sfaxi
 
Python Development (MongoSF)
Python Development (MongoSF)Python Development (MongoSF)
Python Development (MongoSF)Mike Dirolf
 
MongoDB - Aggregation Pipeline
MongoDB - Aggregation PipelineMongoDB - Aggregation Pipeline
MongoDB - Aggregation PipelineJason Terpko
 
MongoDB - Sharded Cluster Tutorial
MongoDB - Sharded Cluster TutorialMongoDB - Sharded Cluster Tutorial
MongoDB - Sharded Cluster TutorialJason Terpko
 
Do something in 5 with gas 8-copy between databases
Do something in 5 with gas 8-copy between databasesDo something in 5 with gas 8-copy between databases
Do something in 5 with gas 8-copy between databasesBruce McPherson
 
Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5Rainer Stropek
 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185Mahmoud Samir Fayed
 
SenchaCon 2016: The Once and Future Grid - Nige White
SenchaCon 2016: The Once and Future Grid - Nige WhiteSenchaCon 2016: The Once and Future Grid - Nige White
SenchaCon 2016: The Once and Future Grid - Nige WhiteSencha
 
Taming the beast - how to tame React & GraphQL, one error at a time
Taming the beast - how to tame React & GraphQL, one error at a timeTaming the beast - how to tame React & GraphQL, one error at a time
Taming the beast - how to tame React & GraphQL, one error at a timeSusanna Wong
 
Using MongoDB and Python
Using MongoDB and PythonUsing MongoDB and Python
Using MongoDB and PythonMike Bright
 
Lazy evaluation drupal camp moscow 2014
Lazy evaluation drupal camp moscow 2014Lazy evaluation drupal camp moscow 2014
Lazy evaluation drupal camp moscow 2014Evgeny Nikitin
 
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)Sirar Salih
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Tsuyoshi Yamamoto
 
Managing Data and Operation Distribution In MongoDB
Managing Data and Operation Distribution In MongoDBManaging Data and Operation Distribution In MongoDB
Managing Data and Operation Distribution In MongoDBJason Terpko
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraDeependra Ariyadewa
 

What's hot (20)

MongoDB Chunks - Distribution, Splitting, and Merging
MongoDB Chunks - Distribution, Splitting, and MergingMongoDB Chunks - Distribution, Splitting, and Merging
MongoDB Chunks - Distribution, Splitting, and Merging
 
Dbabstraction
DbabstractionDbabstraction
Dbabstraction
 
Google cloud datastore driver for Google Apps Script DB abstraction
Google cloud datastore driver for Google Apps Script DB abstractionGoogle cloud datastore driver for Google Apps Script DB abstraction
Google cloud datastore driver for Google Apps Script DB abstraction
 
Lab1-DB-Cassandra
Lab1-DB-CassandraLab1-DB-Cassandra
Lab1-DB-Cassandra
 
Python Development (MongoSF)
Python Development (MongoSF)Python Development (MongoSF)
Python Development (MongoSF)
 
MongoDB - Aggregation Pipeline
MongoDB - Aggregation PipelineMongoDB - Aggregation Pipeline
MongoDB - Aggregation Pipeline
 
Goa tutorial
Goa tutorialGoa tutorial
Goa tutorial
 
MongoDB - Sharded Cluster Tutorial
MongoDB - Sharded Cluster TutorialMongoDB - Sharded Cluster Tutorial
MongoDB - Sharded Cluster Tutorial
 
Do something in 5 with gas 8-copy between databases
Do something in 5 with gas 8-copy between databasesDo something in 5 with gas 8-copy between databases
Do something in 5 with gas 8-copy between databases
 
Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5
 
The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185The Ring programming language version 1.5.4 book - Part 40 of 185
The Ring programming language version 1.5.4 book - Part 40 of 185
 
SenchaCon 2016: The Once and Future Grid - Nige White
SenchaCon 2016: The Once and Future Grid - Nige WhiteSenchaCon 2016: The Once and Future Grid - Nige White
SenchaCon 2016: The Once and Future Grid - Nige White
 
Taming the beast - how to tame React & GraphQL, one error at a time
Taming the beast - how to tame React & GraphQL, one error at a timeTaming the beast - how to tame React & GraphQL, one error at a time
Taming the beast - how to tame React & GraphQL, one error at a time
 
Using MongoDB and Python
Using MongoDB and PythonUsing MongoDB and Python
Using MongoDB and Python
 
Assist9 bmis
Assist9 bmisAssist9 bmis
Assist9 bmis
 
Lazy evaluation drupal camp moscow 2014
Lazy evaluation drupal camp moscow 2014Lazy evaluation drupal camp moscow 2014
Lazy evaluation drupal camp moscow 2014
 
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
Azure Table Storage: The Good, the Bad, the Ugly (15 min. lightning talk)
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
Managing Data and Operation Distribution In MongoDB
Managing Data and Operation Distribution In MongoDBManaging Data and Operation Distribution In MongoDB
Managing Data and Operation Distribution In MongoDB
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and Cassandra
 

Similar to Improving Performance and Flexibility of Content Listings Using Criteria API

Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8Ovadiah Myrgorod
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networkingVitali Pekelis
 
Lift 2 0
Lift 2 0Lift 2 0
Lift 2 0SO
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'sAntônio Roberto Silva
 
The Ring programming language version 1.8 book - Part 50 of 202
The Ring programming language version 1.8 book - Part 50 of 202The Ring programming language version 1.8 book - Part 50 of 202
The Ring programming language version 1.8 book - Part 50 of 202Mahmoud Samir Fayed
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWAREFIWARE
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDMichele Capra
 
Umbraco - DUUGFest 17 -The need for speed
Umbraco - DUUGFest 17 -The need for speedUmbraco - DUUGFest 17 -The need for speed
Umbraco - DUUGFest 17 -The need for speeddawoe
 
Sibelius Seraphini - Relay Modern
Sibelius Seraphini - Relay ModernSibelius Seraphini - Relay Modern
Sibelius Seraphini - Relay ModernReact Conf Brasil
 
Datagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and BackgridDatagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and BackgridGiorgio Cefaro
 
Datagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and BackgridDatagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and Backgrideugenio pombi
 
Universal JS Applications with React
Universal JS Applications with ReactUniversal JS Applications with React
Universal JS Applications with ReactThanh Trần Trọng
 
Jsp/Servlet
Jsp/ServletJsp/Servlet
Jsp/ServletSunil OS
 
Engage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 TagEngage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 TagWebtrends
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRick Copeland
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices -  Michael HacksteinNoSQL meets Microservices -  Michael Hackstein
NoSQL meets Microservices - Michael Hacksteindistributed matters
 

Similar to Improving Performance and Flexibility of Content Listings Using Criteria API (20)

Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8Using Backbone.js with Drupal 7 and 8
Using Backbone.js with Drupal 7 and 8
 
Advanced #2 networking
Advanced #2   networkingAdvanced #2   networking
Advanced #2 networking
 
Backbone js-slides
Backbone js-slidesBackbone js-slides
Backbone js-slides
 
Backbone js
Backbone jsBackbone js
Backbone js
 
Lift 2 0
Lift 2 0Lift 2 0
Lift 2 0
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
The Ring programming language version 1.8 book - Part 50 of 202
The Ring programming language version 1.8 book - Part 50 of 202The Ring programming language version 1.8 book - Part 50 of 202
The Ring programming language version 1.8 book - Part 50 of 202
 
Developing your first application using FIWARE
Developing your first application using FIWAREDeveloping your first application using FIWARE
Developing your first application using FIWARE
 
Developing application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDDDeveloping application for Windows Phone 7 in TDD
Developing application for Windows Phone 7 in TDD
 
Ch05 state management
Ch05 state managementCh05 state management
Ch05 state management
 
Umbraco - DUUGFest 17 -The need for speed
Umbraco - DUUGFest 17 -The need for speedUmbraco - DUUGFest 17 -The need for speed
Umbraco - DUUGFest 17 -The need for speed
 
Sibelius Seraphini - Relay Modern
Sibelius Seraphini - Relay ModernSibelius Seraphini - Relay Modern
Sibelius Seraphini - Relay Modern
 
Datagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and BackgridDatagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and Backgrid
 
Datagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and BackgridDatagrids with Symfony 2, Backbone and Backgrid
Datagrids with Symfony 2, Backbone and Backgrid
 
Universal JS Applications with React
Universal JS Applications with ReactUniversal JS Applications with React
Universal JS Applications with React
 
Jsp/Servlet
Jsp/ServletJsp/Servlet
Jsp/Servlet
 
Engage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 TagEngage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 Tag
 
Paging Like A Pro
Paging Like A ProPaging Like A Pro
Paging Like A Pro
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
 
NoSQL meets Microservices - Michael Hackstein
NoSQL meets Microservices -  Michael HacksteinNoSQL meets Microservices -  Michael Hackstein
NoSQL meets Microservices - Michael Hackstein
 

More from Nils Breunese

Kotlin: a better Java
Kotlin: a better JavaKotlin: a better Java
Kotlin: a better JavaNils Breunese
 
HTTP API for Free? Check out CouchDB
HTTP API for Free? Check out CouchDBHTTP API for Free? Check out CouchDB
HTTP API for Free? Check out CouchDBNils Breunese
 
Website-tool: CMS of Framework
Website-tool: CMS of FrameworkWebsite-tool: CMS of Framework
Website-tool: CMS of FrameworkNils Breunese
 

More from Nils Breunese (6)

Kotlin: a better Java
Kotlin: a better JavaKotlin: a better Java
Kotlin: a better Java
 
NLJUG J-Fall 2011
NLJUG J-Fall 2011NLJUG J-Fall 2011
NLJUG J-Fall 2011
 
NLJUG J-Fall 2011
NLJUG J-Fall 2011NLJUG J-Fall 2011
NLJUG J-Fall 2011
 
HTTP API for Free? Check out CouchDB
HTTP API for Free? Check out CouchDBHTTP API for Free? Check out CouchDB
HTTP API for Free? Check out CouchDB
 
Website-tool: CMS of Framework
Website-tool: CMS of FrameworkWebsite-tool: CMS of Framework
Website-tool: CMS of Framework
 
WSO2 Mashup Server
WSO2 Mashup ServerWSO2 Mashup Server
WSO2 Mashup Server
 

Recently uploaded

AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfproinshot.com
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesVictorSzoltysek
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech studentsHimanshiGarg82
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnAmarnathKambale
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 

Recently uploaded (20)

AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM TechniquesAI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
AI Mastery 201: Elevating Your Workflow with Advanced LLM Techniques
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 

Improving Performance and Flexibility of Content Listings Using Criteria API

  • 1. Improving Performance and Flexibility of Content Listings Using Criteria API Nils Breunese
  • 2. Public Broadcaster since 1926 The Netherlands
  • 3. Online since 1994 Open-source CMS released in 1997
  • 4. Using Magnolia since 2010 Still migrating websites
  • 5. Tens of thousands of pages Multiple sites like that
  • 7. Thanks for the warning… Even 10 seconds would be way too long WARN info.magnolia.module.cache.filter.CacheFilter -- The following URL took longer than 10 seconds (63969 ms) to render. This might cause timeout exceptions on other requests to the same URI.
  • 8. Overview models Standard Templating Kit
  • 9. Tracking back from the template newsOverview.ftl (...) [#assign pager = model.pager]
 [#assign newsList = cmsfn.asContentMapList(pager.pageItems)!] (...)
  • 10. Constructing the pager AbstractItemListModel public STKPager getPager() throws RepositoryException {
 (...)
 return new STKPager(currentPageLink, getItems(), content);
 }
  • 11. Four step pipeline AbstractItemListModel public Collection<Node> getItems() throws RepositoryException {
 List<Node> itemsList = search();
 
 this.filter(itemsList);
 this.sort(itemsList);
 itemsList = this.shrink(itemsList);
 
 return itemsList;
 } 1 2 3 4
  • 12. Step 1a: Constructing the query TemplateCategoryUtil public static List<Node> getContentListByTemplateNames(...) { (...) StringBuffer sql = new StringBuffer( "select * from nt:base where jcr:path like '" + path + "/%'"); (...add 'mgnl:template=' clauses...) (...add 'ORDER BY' clauses...)
 return getWrappedNodesFromQuery(sql.toString(), repository, maxResultSize); } maxResultSize == Integer.MAX_VALUE
  • 13. Step 1b: Executing the query TemplateCategoryUtil public static List<Node> getContentListByTemplateNames(...) { (...)
 NodeIterator items = QueryUtil.search( repository, sql.toString(), Query.SQL, NodeTypes.Content.NAME); }
  • 14. Step 2: Filtering the item list STKDateContentUtil public static void filterDateContentList(...) {
 CollectionUtils.filter(itemsList, new Predicate() {
 @Override
 public boolean evaluate(Object object) {
 (...) return date.after(minDate) && date.before(maxDate);
 }
 });
 }
  • 15. Step 3: Time to sort STKDateContentUtil public static void sortDateContentList(...) {
 Collections.sort(itemsList, new Comparator<Node>() {
 @Override
 public int compare(Node c1, Node c2) {
 (...)
 if (StringUtils.equals(sortDirection, ASCENDING)) {
 return date2.compareTo(date1);
 }
 return date1.compareTo(date2);
 }
 });
 }
  • 16. Step 4: Shrinking the list STKTemplatingFunctions public List<Node> cutList(List<Node> itemsList, final int maxResults) {
 if (itemsList.size() > maxResults) {
 return itemsList.subList(0, maxResults);
 }
 return itemsList;
 } NewsOverviewModel passes Integer.MAX_VALUE, so shrink does effectively nothing in this case
  • 17. Step 5: Get the items from the pager STKPager public Collection getPageItems() {
 
 Collection subList = items;
 int offset = getOffset();
 if (count > 0) {
 int limit = maxResultsPerPage + offset;
 if (items.size() < limit) {
 limit = count;
 }
 subList = ((List) items).subList(offset, limit);
 
 }
 return subList;
 } maxResultsPerPage is typically something like 20
  • 18. When this becomes a problem We have multiple sites like this select * from nt:base where jcr:path like '/siteX/news/%' AND mgnl:template = 'standard-templating-kit:pages/stkNews' 20000 pages under website:/siteX/news Four step pipeline returns STKPager with 20000 items (page nodes) [#assign model.pager] [#assign newsList = cmsfn.asContentMapList(pager.pageItems)!] STKPager returns list with 20 page nodes 19980 Node objects created, but not rendered
  • 19. A query could do all steps at once JCR queries are pretty flexible
  • 20. Everything in a single JCR query Only 20 nodes returned SELECT * FROM nt:base WHERE jcr:path LIKE '/siteX/news/%' AND mgnl:template = 'standard-templating-kit:pages/stkNews' AND jcr:created < cast('2016-06-07T00:00:00.000Z' AS DATE) ORDER BY date ASCENDING LIMIT 20 OFFSET 20 Search Filter Sort Paging
  • 21. Criteria API For those familiar with Hibernate/JPA Criteria criteria = JCRCriteriaFactory.createCriteria()
 .setBasePath("/siteX/news")
 .add(Restrictions.eq( "@mgnl:template", "standard-templating-kit:pages/stkNews"))
 .add(Restrictions.betweenDates("@jcr:created", minDate, maxDate))
 .addOrder(Order.asc("date"))
 .setPaging(20, 1); 
 ResultIterator<...> items = criteria.execute(session).getItems(); Sort Paging Filter Search
  • 22. Criteria API for Magnolia CMS Magnolia module by Openmind
  • 24. Custom pager Only a single page worth of items public class VtkPager<T> extends STKPager { 
 private final List<? extends T> items; private final int pageSize;
 private final int count;
 
 (...)
 
 @Override
 public List<? extends T> getPageItems() {
 return items;
 } }
  • 25. Use it in your model classes VtkContentListModel (vpro) public abstract class VtkContentListModel ... {
 
 protected final VtkPager<ContentMap> pager;
 
 @Override
 public String execute() {
 pager = createPager();
 return super.execute();
 }
 
 protected abstract VtkPager<T> createPager(); (...) }
  • 26. Concrete Example VtkNewsOverviewModel (vpro) @Override
 protected VtkPager<Node> createPager() { (...)
 AdvancedResult result = JCRCriteriaFactory.createCriteria()
 .setBasePath(path)
 .add(Restrictions.in("@mgnl:template", templates))
 .add(Restrictions.betweenDates("@jcr:created", minDate, maxDate)) .addOrder(Order.asc("date")) .setPaging(itemsPerPage, pageNumberStartingFromOne) .execute(session);
 List<Node> items = new ArrayList<>();
 for (AdvancedResultItem item : result.getItems()) {
 items.add(item.getJCRNode());
 }
 
 int count = result.getTotalSize();
 
 return new VtkPager<>(link, items, content, itemsPerPage, count); }
  • 27. Still this. Was it all for nothing? :o( WARN info.magnolia.module.cache.filter.CacheFilter -- The following URL took longer than 10 seconds (63969 ms) to render. This might cause timeout exceptions on other requests to the same URI.
  • 28. Example VtkNewsOverviewModel (vpro) @Override
 protected VtkPager<Node> createPager() { (...)
 AdvancedResult result = JCRCriteriaFactory.createCriteria()
 .setBasePath(path)
 .add(Restrictions.in("@mgnl:template", templates))
 .add(Restrictions.betweenDates("@jcr:created", minDate, maxDate)) .addOrder(Order.asc("date")) .setPaging(itemsPerPage, pageNumberStartingFromOne) .execute(session);
 List<Node> items = new ArrayList<>();
 for (AdvancedResultItem item : result.getItems()) {
 items.add(item.getJCRNode());
 }
 
 int count = result.getTotalSize();
 
 return new VtkPager<>(link, items, content, itemsPerPage, count); } This call takes 10-60+ seconds!
  • 29. AdvancedResultImpl (jcr-criteria) @Override
 public int getTotalSize() {
 if (totalResults == null) {
 int queryTotalSize = -1;
 try { // jcrQueryResult instanceof JackrabbitQueryResult) {
 Method m = jcrQueryResult.getClass().getMethod("getTotalSize");
 queryTotalSize = (int) m.invoke(jcrQueryResult);
 } catch (InvocationTargetException | IllegalAccessException e) {
 LOG.error(e.getMessage(), e);
 } catch (NoSuchMethodException e) {
 
 }
 if (queryTotalSize == -1 && (itemsPerPage == 0 || applyLocalPaging)) {
 try {
 totalResults = (int) jcrQueryResult.getNodes().getSize();
 } catch (RepositoryException e) {
 // ignore, the standard total size will be returned
 }
 }
 
 if (queryTotalSize == -1) {
 totalResults = queryCounter.getAsInt();
 } else {
 totalResults = queryTotalSize;
 
 }
 }
 return totalResults;
 } We end up here
  • 30. jackrabbit-core 2.8.0 protected void getResults(long size) throws RepositoryException {
 (...)
 result = executeQuery(maxResultSize); // Lucene query (...) // Doesn’t use result.getSize(), call collectScoreNodes(...) } private void collectScoreNodes(...) {
 while (collector.size() < maxResults) {
 ScoreNode[] sn = hits.nextScoreNodes(); (...)
 // check access
 if (isAccessGranted(sn)) {
 collector.add(sn);
 } else {
 invalid++;
 }
 }
 } QueryResultImpl
  • 31. It used to be fast! https://issues.apache.org/jira/browse/JCR-3858
  • 32. jackrabbit-core 2.10.0+ protected void getResults(long size) throws RepositoryException { (...) if (sizeEstimate) {
 numResults = result.getSize(); // Use count from Lucene
 
 } else {
 // do things the Jackrabbit 2.8.0 way
 (...)
 } (...) } QueryResultImpl
  • 33. Enable Jackrabbit’s 'sizeEstimate' Jackrabbit 2.10+ <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex"> (...) <param name="sizeEstimate" value="true"/> </SearchIndex>
  • 34. Rendering times down to 1-2 seconds Bingo
  • 36. Feel free to contact me Nils Breunese @breun n.breunese@vpro.nl