Sunday, June 1, 2008

Here is a GroupingCollection with good performance !

I created a new GroupingCollection2 (by tweaking the default implemenation) which has better performance compared to the GroupingCollection. Please find the swc here.

Replace the GroupingCollection instance in any application with GroupingCollection2 and check the performance. When I tested it with 8K records with 4 grouping fields it was able to group in 5 seconds which seems to be good (in comparsion).

Please note this has not gone through extensive testing. I would be glad to fix any bugs found.

If you are one of those who doesn't have patience to build and test an app, here is the one I built. Here is the source.

If you think it is worth your time drop a note about your findings !!

78 comments:

Hem Talreja said...

Awesome,

This works like a charm.

Note: the a-sync refresh option is a little slow however, this is not a problem as the grouping of the collection with summaries is fast enough....

Vinod said...

hi, I was wondering if you could share the source code of GroupingCollection2.
We are not able to get the good performance, so may be we can optimize it further.

Thanks,
Vinod

Sreenivas said...

If you can send me a sample which doesn't show any improvement I will try to fix it. So that every one can benefit.


I cannot share the source as of now.

Vinod said...

hi sreenivas,
thanks for your response. It would be difficult for me to send you the sample, as we are using it in a complex financial application, and we are using BlazeDS, custom renderers and lot of custom coding.

It would be a pretty complicated for me to make a sample for this purpose. We thought we will debug the new grouping collection and try to see if we can optimize it for our application.

Sreenivas said...

If the fix I have done is not working for you then I think you can still work on the GroupingCollection source available for the default implementation and try to improve the performance of that one. If you can improve the performance or atleast even tell me where you see the performance problem I can work on improving it.

Wayne Babich said...

Unfortunately, I'm seeing no improvement.
About 3000 rows, grouped at three levels with four SUM summary fields. About 25 seconds. Same as with the original GroupingCollection.

But I'm new to FLEX development and don't know how to be sure that I'm using GroupingCollection2 instead of GroupingCollection. Maybe the other code is being linked in instead? Is there a way I can be sure that I'm running with the code that is in the new grouping.swc file?

BTW: My code looks like this:

public class CRDDataGrid extends AdvancedDataGrid {
private var myGroupCollection:GroupingCollection2 = new GroupingCollection2();

etc.

Sreenivas said...

Hi Wayne,

because you are referring to GroupingCollection2 I am sure the new code is being used.

A test case with summary fields may not show improvement due to the reasons mentioned by Doug in comments sections of this post.

I would urge you to run the test without summary fields and see if you find any improvement.

I would appreciate if you can let me know your findings in that case.

Wayne Babich said...

Thanks Sreenivas.
I ran a test with 2859 rows
Two levels of grouping. The results were surprising:

Using GroupingCollection2:
4 SUM summary fields: 16 seconds
no summary fields: 13 seconds


Using GroupingCollection:
4 SUM summary fields: 18 seconds
no summary fields: 14 seconds

Is there something I could be doing wrong?

BTW: Additional levels of grouping seem to make the numbers significantly higher.

Sreenivas said...

Would it be possible to mail me sample code+data? I can test it at my end and see if it is problem with test code or a real problem.

Vijay said...

hi Sreenivas..thanks for the GroupingCollection2. I see noticable performance improvement compared to the one provided by Flex Framework. Do u have any suggestions for using Summaries along with ur groupingCollection2?
Performance is good only If i dont use summaries. Any suggestions on improving performance of grouping along with summaries ?

here is my grouping code
private function updateGrouping():void {

var groupingCollection:GroupingCollection2 = new GroupingCollection2();
var grouping:Grouping = new Grouping();
var groupingField:GroupingField;

grouping.fields = new Array();

groupbyeditor.selectedDataFields.split(',').forEach(
function(element:*, index:int, arr:Array):void{
groupingField = new GroupingField(element);
var summaryRow:SummaryRow = new SummaryRow();
summaryRow.summaryPlacement = "group";
summaryRow.fields = summaryFields;
//groupingField.summaries = [summaryRow]; // this line brings down performance
groupingCollection.source=_report.reportData;
grouping.fields.push(groupingField);
groupingCollection.grouping = grouping;
});

if(groupbyeditor.selectedDataFields){
groupingCollection.refresh();
}
dataGrid.dataProvider = groupbyeditor.selectedLabels?groupingCollection:_report.reportData;
}

Vijay Mareddy said...

Hi Sreenivas,
My report has 15000 rows.
My grouping is fine but when i do a grouping with simple summary(i.e. SUM operation)..i get this
Error #1502: A script has executed for longer than the default timeout period of 15 seconds.

yes i already set this on my Application tag
scriptTimeLimit="60"
I am using the GroupingCollection2 with async refresh.

Do you suggest i do the summary calculations after the regular grouping is done that is after the groupingCollection2.refresh()? Was the groupingCollection2 meant to be this way? that is separate the summary calc part from grouping part...?

Michael van Leest said...

SWEET!!! instead of 20 to 30 seconds doing a async refresh, it's now a 3 seconds instant refresh!!

Incredible. This is going straight into production! Thanks a million! You made a sort of useful component, a A+ component :-) Keep up the great work...

oldmonk said...

hi sreenivas,
is there anyway to access the grouped data (as a flat list) from a grouping collection without using AdvancedDataGrid? I want to create several groups from flat data and use it in other controls like charts.
Thanks,
Ram

Sreenivas said...

You can access the grouped collection as a flat collection by passing it through HierarchicalCollectionView and using its iterator. You would be required to set all the nodes as open.

Vijay Mareddy said...

Should i continue with the Groupingcollection2 even after migrating to 3.0.2 ?
Is Groupingcollection2 same as mx.collections.GroupingCollection in the 3.0.2?

Sreenivas said...

The changes in GC2 are not available in 3.0.2.

They might become available in the next release.

Adam said...

hi sreenivas,
thanks for this, i'm getting a significant performance increase over 3.0.2 GroupingCollection.
i think i've found a bug though: i've got an adg with your gc2 as a dataprovider. i find that the vertical scrollbar is not behaving properly (remains disabled) in the case when the all the group items in the adg are closed, but the number of groups exceed the vertical space of the adg. the moment i expand even one group the vertical scrollbar begins to behave properly again (is enabled).
any thoughts?

Sreenivas said...

The bug should exist whether you use GC2 or not. Let me know if that is not the case.

Are you using variableRowHeight flag set to true ?

If you have a sample which can be compiled run independently I can take a look.

S said...

Hi Sreenivas

I am using the Advanced Data Grid to display the the data in the tree structure.
I am suppose to display the root value with another value.
For example
Employee: 1 Name:XYZ Organization: IBM
Employee: 2 Name:XYZ Organization: VERIZON
Employee: 3 Name:XYZ Organization: IBM
Employee: 4 Name:XYZ Organization: VERIZON
Employee: 5 Name:XYZ Organization: IBM
Employee: 6 Name:XYZ Organization: BOA
Employee: 7 Name:XYZ Organization: IBM
When I use the Grouping Collection with the grouping field as Organization I will get the out put as

BOA
Employee: 6 Name:XYZ
IBM
Employee: 1 Name:XYZ
Employee: 3 Name:XYZ
Employee: 5 Name:XYZ
Employee: 7 Name:XYZ
VERIZON
Employee: 2 Name:XYZ
Employee: 4 Name:XYZ

But I need the out put like

BOA(1)
Employee: 6 Name:XYZ
IBM(4)
Employee: 1 Name:XYZ
Employee: 3 Name:XYZ
Employee: 5 Name:XYZ
Employee: 7 Name:XYZ
VERIZON(2)
Employee: 2 Name:XYZ
Employee: 4 Name:XYZ

Organization(*)- In this * value represent the number of rows in each organization. How to get this and how to show like above?

Sreenivas said...

You can use the COUNT summary function to say count the employee data field and then use groupLabelFunction to display it display it along with the group label. Or you can use the summaryPlacement="group" to display it in a separate column.

mayank.1941 said...

I'm working on a paginated list that throws an ItemPendingError when the requested data
has not yet been loded.

It seems that I may have discivered a bug in GroupingCollection that prevents such usage:

Looking at GroupingCollection : 1252,
1) ItemPendingError is caught in side buildGroups function
2) the exception block invokes cleanUp()
3) Clenup sets flatCursor=null
4) back in the buildGroups() the code continues, as the excption is inside a while loop
started on line 1191, thus the flatCursor is now null, throwing a null object error.

Tried the same with GroupingCollection2 and the same problem.
Can you look into this and put a patch that I can try for you.

Surender said...

Hi Sreenivas...
I am using grouping in advance data grid.
I have BU and under BU we Have Sub BU.

Every BU has its code no and SUB BU has its own code no.both codes are alphanumeric.

Now i want to do grouping based on BU and in the next column code will come .Now iam wondering can i use this code as summary field that to be placed at group level?At group level BU will come and its code in next column.when we expand the BU it should show SUB BU and their corresponding code in next column.There is no calculation required to be done for summary.Can i acheive this...

Surender said...

Hi
how can i use ur swc file i tried adding it to flex builder path but when i try to use it it doesnt show groupingcollection2 in option.

Sreenivas said...

This is the first time I hearing about the swc problem.

Sreenivas said...

To show BU and SUB-BU id numbers you can try to use GroupingField.groupingObjectFunction by maintining a map of BU names and their id numbers.

Surender said...

Hi srinivas ,

Thanks for your prompt reply.

well iam new to flex and I cant understand much of whatever u said.
Could u pls post an example with that MAP being an arrayCollection.

I would be very thankful to u...

mayank.1941 said...

Sreenivas:

Any comments to my post above re error on remote data fetch.

Sreenivas said...

Yes. You have found a bug. Please log it in the JIRA bug base so that it can be fixed.

I think the exception handler should have just returned.

Sreenivas said...

On second thoughts the code should never get a ItemPendingError in that area because all ItemPendingErrors would have occured when sorting is done in
makeGroupedCollection.

mayank.1941 said...

Sreenivas,

I have a lot of data, (4000+) rows, thus I can't afford to have everything fetched locally, thus the sorting is done on the server. This includes the group sorting and additional columns. Thus, the ItemPendingError can occur.

I have opened this issue in JIRA. How does the issues there get prioritized?

mayank.1941 said...

To add to my comment above. My collection caches a finite # of rows to conserve on memory, thus rows can come and be removed, then latter reloaded.

Sreenivas said...

As the GC code tries to sort all the data just before it tries to build the groups 'data' cannot be missing. Right ?

mayank.1941 said...

Sreenivas,

In my case the data can be missing, as I my list keeps at most 2000 rows locally, whereas the data set contains a total of 4000 rows, thus during the sort data can come and go. Also, in my implementation, I use the server to actually sort to avoid bringing it all down to the client. Thus, yes, right after sort, I can have missing data.

Sreenivas said...

May be we are not communicating effectively. Do yo mean to say if we have following code data can be missing when buildGroups is called?

dataArray.sort();
buildGroups(dataArray);

That would be really strange. Anyway if that is the case I am afraid you are on your own. You need to modify the GC code to address this need.

a. Remove the sorting logic.
b. Make it build group over iterations similar to async refresh, that is after itemPendingError continue to build the groups without clearing previous results.

Tom said...

Hi Sreenivas,

Thx for all your great in depth posts. Can you at all comment on the future of DMV and ADG specifically? I heard that Flex 4 won't get an updated grid component at first. Looking at the diff between Flex 3.2 and Flex 3.3 there were next to no changes, is ADG still being actively supported? are you guys working on the next version? Will the India team continue working on DMV?

I think we all realize its a very hard problem to solve to make a performant grid with so many advanced features.

Andrew said...

I love the performance. The tree that it builds is always collapsed. Is there any chance it could follow the displayItemsExpanded Boolean in the AdvancedDataGrid?

Sreenivas said...

Tom: I would post my thoughts on future of DMV/ADG soon.

Andrew : The control of displaying nodes rests with ADG. GC is just a provider of data.

So if you set the flag on ADG you should be getting the required fully expanded view. If you are not getting it, it is a bug (I think).

Andrew said...

I think there's a bug with displayItemsExpanded on the ADG then. Is there some interface you aren't implementing on the groupingcollection2 that happens on the groupingcollection?

Also, do you plan to work in an asyn option on the refresh(asyn:Boolean = false)? The groupingcollection2 seems to work asyncronously but isn't providing updates as groups are assembled. I may be the fact that you're using a better algorithm than groupingcollection.

Vijay Mareddy said...

Sreenivas,
Would it be possible to release the GroupingCollection2 with the following JIRA fixed?
Fairly easy one to fix :)

http://bugs.adobe.com/jira/browse/SDK-20175

Vijay Mareddy said...

Adam,
Been there done that.
I had the same problem and resolved it by doing the following
1. You need to wrap ur GC into a HierarchicalCollectionView.
2. By commenting out the 'then' condition and just using the 'else' part in the following code:
//if(dataGrid.dataProvider is HierarchicalCollectionView){
// ((dataGrid.dataProvider as HierarchicalCollectionView).source as GroupingCollection2).source.filterFunction = filterFunc;
// ((dataGrid.dataProvider as HierarchicalCollectionView).source as GroupingCollection2).refresh();
//} else {
dataGrid.dataProvider.filterFunction = filterFunc;
dataGrid.dataProvider.refresh();
//}

After the above change, i ended up with this new bug (with workaround):

http://bugs.adobe.com/jira/browse/SDK-20175

Please vote for the bug.

====================
Quote from Adam from previous comments.
"i find that the vertical scrollbar is not behaving properly (remains disabled) in the case when the all the group items in the adg are closed, but the number of groups exceed the vertical space of the adg. the moment i expand even one group the vertical scrollbar begins to behave properly again (is enabled)."

DEVSACHIN said...

Hi,
i have added ur swc to my project and use GroupingCollection2.after that i am testing it for 30 rows..but it is not working. i means it is not making grouped data , just show flat data..[same code is working with GroupingCollection].
i have created Grouping collection by action script.

help me
Thanks

DEVSACHIN said...

Its very fast..i have tested it with 500 rows..it is 8 times faster than previous one..only takes 250 around time..but old GP takes 1800/1600 around time for 500 rows.

:)
:)
Heartily Thanks to give a good component, really i needed it this time.

Regards
Sachin
Flex and AS3 developer

Thanks

DEVSACHIN said...

Hi Sreeninas,

It has poor performane with expandall() method..Because it takes 40 seconds(more than half minute) to expand 500 rows..
Please check this, also give me any solution to this

Thanks
Sachin

Sreenivas said...

expandAll performance is controlled by ADG not GC. Anyway I will take a look and let you know if there are tweaks that can be done to improve it.

What is the total number of rows in your dataprovider ?

DEVSACHIN said...

I am creating 500 rows on the fly n then assign it to grid..means 500 rows in dataprovider.

One more thing
please find my one more query at http://www.nabble.com/-flex_india:18976--I-am-not-able-to-set-Disclosureicon-of-AdvancedDataGridListData-at--rumtime-in-FLEX-3-td21868443.html

Thanks
Sachin

Sreenivas said...

You should be able to just set the disclosure icon style to null and get what you need.

DEVSACHIN said...

Yes it should be, but it was not happening. value is not being set to null for that row.

DEVSACHIN said...

Hi,
i am creating column of a custom Datagrid component at runtime.so i do not specify any column at design time. i only declear datagrid component and its ID and width-height property.but before columns are added to the grid, grid falls into callLaterDispatcher event of UIComponent..
So, it is creating a long delay to appear datagrid in the application.
Please let me know about the solution,if any.

Thanks
Sachin dev tripathi

iamprofchaos said...

I tried the groupingcollection2 against the flex groupingcollection, and was very disappointed....

463 records, 2 grouping collections

groupingcollection : 41s
groupingcollection2: 51s

... I get even worse timings with this.

DEVSACHIN said...

delete old post..it has some mistakes

HI,
i want to change the display of grouping text.i am doing grouping on "Date" field and it shows long date format in grouping.i used groupingObjectFunction to apply DateFormatter on the data.it change the format on the column,in which i applied grouping but it do not change grouped heading(which displays with "+" icon).

Thanks
Sachin Dev Tripathi

Andrew said...

Check out groupLabelFunction on the AdvancedDataGrid.

DEVSACHIN said...

Hi,
I am using groupLabelFunction in my custom Datagrid component. I want to format the display of groupLabel according to its data type. if it is Long datetime value then I want to use dateformatter to change it to MM/DD/YYYY format. But in the first argument (i.e. item:Object), the GroupLabel property has text type of data. So I am usable to detect its data type.
I am using dummy column to show grouping information. So the second argument of GroupLabelfunction( i.e. col:AdvancedDataGridColumn) has no datafield and header text.
Please help me how can I accomplish my work

neogenesis said...

good work, it helped me to cut the process time more than half of my original code. thanks!

Sarath&Madhavi said...

Srinivas..

I have a large dataset with 120 columns with average of 100px width for each column... and using displayItemsExpanded which is freezing my brwser..any solution would be apprecuiated

--Sarath

Ramesh said...

Good work Sreenivas.

Is it possible for you to enable/disable the (default) sort option based on a flag in GC2. I want to display my records in the same order as provided to the GC2.
GC also does not have this feature, if you can do this in GC2 that would be more helpful.

I noticed in the other forums most of the people looking for this option as they do not want the GC to sort its own.

Thanks!

Sreenivas said...

To group items properly and efficiently it is very much required to sort the input.

So I think it is not easy to provide this option.

Vijay Mareddy said...

GroupingCollection2.refresh(true) does not render one at a time instead it is rendering the whole report all at once.

Sreenivas said...

I figured out that the improvement provided by GC2 is mainly because it uses code which doesn't trigger the collection update event when groups are being updated/formed. Due to some reason the collection update event is taking lot more time than it should actually take.

So for users who want to use displayItemExpanded or async refresh it is not possible to provide boost in performance till the collection update event mechanism performance is improved.

Sreenivas said...

DEVSACHIN: I don't know whether you figured out a solution for your date format problem. If you have not you can send me some sample code showing what you are trying to achieve or an image I can take a look.

DEVSACHIN said...

Hi,
I have sent you the sample project at your gmail id.pLease let me know if you find it..Please reply my previous mail also if posible..
Heartely Thanks
-Sachin

DEVSACHIN said...

@S:
for your requirment of this
IBM(4)
Employee: 1 Name:XYZ
Employee: 3 Name:XYZ
Employee: 5 Name:XYZ
Employee: 7 Name:XYZ
VERIZON(2)
Employee: 2 Name:XYZ
Employee: 4 Name:XYZ
Solution is already in this blog
this is(u shud find it):
//groupLabelFunction of adg
private function addChildCount(data:Object,col:AdvancedDataGridColumn):String
{
//get the groupingCollection to get access to the group label property name
var grp:IGroupingCollection = adg.dataProvider.source as GroupingCollection;
var grpLabelProperty:String = grp.grouping.label;

//if item is closed append child count
if (adg.isItemOpen(data))
return data[grpLabelProperty] ;
else
{
//get child count for the group
// this uses the fact that IHierarchicalData supplied as dataProvider to ADG gets
// converted to a IHierarchicalCollectionView. This converts all children to ICollectionViews if they are not already.
var childCount:int = adg.dataProvider.getChildren(data).length;
return data[grpLabelProperty] + "(" + childCount + ")";
}
}
//if u send me mail id then i can send u sample.

Dharmendra said...

Hi Sreenivas,
Performace of GC2 is awesome. However I found an issue with Collection update event.

GC2 does not seems to support high volume collection update , it just goes in to non-responding mode and take long time to come back in to normal state.
this is very critical for financial application where update are commons.

Can u pls have a look in to it ?

Thanks,
Dharmendra

Sreenivas said...

As I have mentioned in once of the comments due to the current way of summary computation it cannot handle high volume updates. It may get addressed in the next release.

Tom said...

Any chance you can open up the code now that DMV source is available (but still under license of course)?

Sreenivas said...

The modifications I had done for the improvement have been incorporated into the Flex 4 DMV source. So the changes would be available as and when that source gets released.

Tom said...

But is it not possible to release the code for Flex 3.4 and leave it up to the developer to integrate, no need to make it official part of DMV? The main reason for using your great control is because for us, waiting for Flex 4 is not an option.

Sreenivas said...

Here is the modified source

Dharmendra said...
This comment has been removed by the author.
Dharmendra said...

Hi Shreenivas,
Did you get chance to look in to high volume updates issue of groupingCollection2.

We are stuck with this issue,pls have a look and propose some workaround.

Regards,
Dharmendra

Sreenivas said...

I think regarding this Sameer has already asked you a question for which you have not responded.

http://bugs.adobe.com/jira/browse/FLEXDMV-1689

I don't think we can scale GC or GC2 for real time updates beyond some number.

Dharmendra said...

Hi Sheenivas,
I have replied to Sameer.

'GC2 cant be scalled to support high volum updates' Does that mean Flex Grouping is not appropiate solution for hight volume real time application. What other componenst of flex can suffice our need ?

we need support for 10 update/sec and CG2 only suppprts 4 update/sec

Please advise us as to what is the best solution for such scenario.

Regards,
dharmenedra

Sreenivas said...

Sameer has placed the recommendation in the bug. To repeat it :

For high volume real time updates it is better to do the job on the server and send the results to the client. This is the recommended practice because we don't expect all client machines to have enough processing power to do the computation.

DEVSACHIN said...

Hi Sreeni,
This post is with referance to post of sameer:
http://techrays.wordpress.com/2008/04/07/advanced-datagrid-as-an-item-renderer-within-an-advanced-datagrid/#comment-1184

Using Ad.DataGrid as item renderer in adv.DataGrid taking much time to collapse the row..ever it takes more time then expanding the row.
Please let me know how i can control over this time..i need the solution urgently because i have to incorporate this feature into our real time application.

Thanks
Sachin

Tom said...

Hi Sreenivas

Do you know any recommended consultants who are experts with the AdvancedDataGrid?

We have a need to extend ADG's functionality. Immediate requirement is to optimize horizontal scrolling to behave the same as vertical. The requirement is not to have simple smooth scrolling but to only instantiate renderers that are in view. This is just the start; there are other features & performance bugs in addition to this one.

Unfortunately we can't wait until 2023 when Flex 5 finally ships with a replacement grid control.

If anyone knows a reputable person please send email to: tntomek at --- hotmail --- com

Sreenivas said...

I don't know of any ADG expert.

If you are not going to use cell spanning feature in your application it should be easy to switch the code to create only visible renderers if it is not already doing it.

vijaykumarreddy said...

Hi Srinivas
I am not able to get the scroll bar for ADG with GC2. I have more records. Can please let us know is some fix is added to resolve this.

srikanth602 said...

Can anybody let me know it you are able to get the list or collection of grouped data from advanced data grid . I am trying to bind this data to piechart . Any suggestions or code would be so much grateful

raja said...

Hi Sreenivas,
In out application we need to display some 10000 rows, 800 columns of data with 500 summary columns & 4 levels of grouping. Could you please suggest me in Choosing the data Provider? I am so confused in choosing Hierarchical Data or Flat Data with Grouping Collection2 functionality.

Please suggest me in choosing this.
Thanks in Advance.