Permlink Replies: 43 - Pages: 3 [ Previous | 1 2 3 | Next ] - Last Post: 26 Sep 19, 21:46 Last Post By: JeffTucker Threads: [ Previous | Next ]
davidekholm

Posts: 3,442
Registered: 18-Oct-2002
Re: Keyword Labels Maxing at 30
Posted: 13 Aug 17, 17:52   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
To gather all keywords used in an album one has to walk the album object tree and gather keywords from each object and feed them to a Set (unique collection). Here's an example:
Set all = new HashSet();
 
void gatherKeywords(AlbumObject folder) {
	for (AlbumObject ao : folder.getChildren()) {
		if (!ao.isIncluded) {
	        	continue;
		}
		if (ao.isFolder()) {
			gatherKeywords(ao);
		}
		for (String kw : ao.getKeywords().split(", ")) {
			all.add(kw);
		}
	}
}
gatherKeywords(rootFolder);
As you notice this is yet another recursive algorithm. I notice several of you aren't comfortable with writing recursive code so I've made a new method for the upcoming jAlbum version that gathers all included descendants of an album object into a collection. All album objects can now be easily iterated. Here are some examples:
Print names of all album objects:
for (AlbumObject ao : rootFolder.getDescendants()) { System.out.println(ao); }
Count all album objects:
rootFolder.getDescendants().size();
Finally, here's the code to gather keywords for all album objects:
Set keywords = new HashSet();
for (AlbumObject ao : rootFolder.getDescendants()) {
	keywords.addAll(ao.getKeywordSet());
}


I'm very excited about this new getDescendants() call. It has the potential to allow parallel processing to significantly speed up lengthy operations on multiple album objects. I'll return with more examples when I've polished performance on this implementation further.
davidekholm

Posts: 3,442
Registered: 18-Oct-2002
Re: Keyword Labels Maxing at 30
Posted: 13 Aug 17, 17:53   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
Do a core update to try out this new API
RobM

Posts: 3,815
Registered: 4-Aug-2006
Re: Keyword Labels Maxing at 30
Posted: 13 Aug 17, 18:43   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
davidekholm wrote:
Do a core update to try out this new API
Will there be a switch in the API so you can decide on getting hidden, included and/or excluded descendant objects?
RobM

Posts: 3,815
Registered: 4-Aug-2006
Re: Keyword Labels Maxing at 30
Posted: 13 Aug 17, 22:07   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
It is easier now :) To make a unique, sorted list, of the keywords (in init.bsh)
Set keywords = new HashSet();
for (AlbumObject ao : rootFolder.getDescendants()) {
	keywords.addAll(ao.getKeywordSet());
}
List sortedList = new ArrayList(keywords);
Collections.sort(sortedList);	
System.out.println(sortedList);
davidekholm

Posts: 3,442
Registered: 18-Oct-2002
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 10:28   in response to: RobM in response to: RobM
  Click to reply to this thread Reply
RobM wrote:
It is easier now :) To make a unique, sorted list, of the keywords (in init.bsh)
Set keywords = new HashSet();
for (AlbumObject ao : rootFolder.getDescendants()) {
	keywords.addAll(ao.getKeywordSet());
}
List sortedList = new ArrayList(keywords);
Collections.sort(sortedList);	
System.out.println(sortedList);

For a sorted set, use TreeSet:
Set keywords = new TreeSet();
for (AlbumObject ao : rootFolder.getDescendants()) {
  keywords.addAll(ao.getKeywordSet());
}
RobM

Posts: 3,815
Registered: 4-Aug-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 11:01   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
davidekholm wrote:
For a sorted set, use TreeSet:
Set keywords = new TreeSet();
for (AlbumObject ao : rootFolder.getDescendants()) {
  keywords.addAll(ao.getKeywordSet());
}
As I suspected, this is a subtle plan to teach us Java, got recursion well now lets move on to something else ;)

Once I get my head around this I think I'm going to really like it :)
davidekholm

Posts: 3,442
Registered: 18-Oct-2002
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 15:03   in response to: RobM in response to: RobM
  Click to reply to this thread Reply
RobM wrote:
davidekholm wrote:
Do a core update to try out this new API
Will there be a switch in the API so you can decide on getting hidden, included and/or excluded descendant objects?

I figured you'd ask about that :-). Get a core update again to enjoy this updated API which allows you to select whether to also include excluded and/or hidden objects.

JavaScript/BeanShell Example (try in the System Console for instance):
var IncludeOption = Java.type("se.datadosen.jalbum.IncludeOption"); // Dump this line if using BeanShell/Java
 
// Count all but hidden and excluded objects
rootFolder.getDescendants().size();
 
// Count all but excluded objects
rootFolder.getDescendants(IncludeOption.HIDDEN).size();
 
// Count all objects
rootFolder.getDescendants(IncludeOption.EXCLUDED, IncludeOption.HIDDEN).size();


This API is available in jAlbum 14.1.4 now. I'll auto-update all jAlbum 14.1 to 14.1.4 as I want to address a CPU eating bug too.
JeffTucker

Posts: 8,039
Registered: 31-Jan-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 15:12   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
Very nice, and with the best default choice - in most cases, a skin wants to know about only included, visible objects.

I'll have a tinker with it later - I've got one recursive in my skins, looking for "new" items, and this should reduce it to about three lines. :)
RobM

Posts: 3,815
Registered: 4-Aug-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 15:22   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
davidekholm wrote:
RobM wrote:
davidekholm wrote:
Do a core update to try out this new API
Will there be a switch in the API so you can decide on getting hidden, included and/or excluded descendant objects?

I figured you'd ask about that :-). Get a core update again to enjoy [this updated API

Thanks, now would anyone want a getAncestors() ;)
Not sure what you could do with ancestors, maybe an easier breadcrumb trail?
JeffTucker

Posts: 8,039
Registered: 31-Jan-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 15:44   in response to: JeffTucker in response to: JeffTucker
  Click to reply to this thread Reply
jGromit wrote:
I'll have a tinker with it later....

Quick initial test tells me that it's working as advertised. Edit: Also tested the logic for hidden and excluded objects, which also looks like it's solid.

RobM wrote:
Not sure what you could do with ancestors, maybe an easier breadcrumb trail?

I've got that routine in two of my skins, adapted from something someone else wrote. I couldn't re-create it from scratch if my life depended on it. ;)
davidekholm

Posts: 3,442
Registered: 18-Oct-2002
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 21:47   in response to: JeffTucker in response to: JeffTucker
  Click to reply to this thread Reply
Thanks for testing guys. Now I'll optimize the internals a bit (and hopefully not break things) and rewrite some jAlbum External Tools and other internal jAlbum logic to use this API instead. There is really no downside to using this API compared to recursive code. It doesn't gather the whole list of all album objects in RAM. Instead, it walks the tree iteratively.

Most developers will probably appreciate the straight forward syntax. Here's a JavaScript example that prints all album object names:
for each(ao in rootFolder.getDescendants()) {
  print(ao);
}
Here is the same code in Java/BeanShell:
for (ao : rootFolder.getDescendants()) {
  System.out.println(ao);
}
You can also use the new cool Stream API of Java 8 to efficiently filter and perform various tasks on album objects using callback functions (aka "lambdas"). Here's a sample that prints the camera dates on all images (expensive operation as it needs to open each file):
var Category = Java.type("se.datadosen.jalbum.Category");
 
rootFolder.getDescendants().stream()
 .filter(function(ao) {  return ao.getCategory() == Category.image } )
 .forEach(
  function(ao) {
     print(ao.getVars().get("originalDate")) 
  }
);
Now, this may not look as straightforward as the plain for each loop, but now study what happens when you swap stream() to parallelStream():
var Category = Java.type("se.datadosen.jalbum.Category");
 
rootFolder.getDescendants().parallelStream()
 .filter(function(ao) {  return ao.getCategory() == Category.image } )
 .forEach(
  function(ao) {
     print(ao.getVars().get("originalDate")) 
  }
);
The Stream API now splits the work of filtering images and gathering camera dates to multiple CPU cores / threads. This can have a significant impact on performance. If your source images resides on a network drive, you may expect performance gains of several hundred percent without having to manually dabble with thread coding.

In plain compiled Java, the equivalent code looks like this. Notice the short syntax:
rootFolder.getDescendants().parallelStream()
   .filter(ao -> ao.getCategory() == Category.image)
   .forEach(ao -> System.out.println(ao.getVars().get("originalDate")));
If you want to use these callback methods in BeanShell you have to resort to using anonymous inner classes as BeanShell doesn't support the neat lambda syntax of Java 8:
import java.util.function.*;
 
rootFolder.getDescendants().parallelStream()
 .filter(new Predicate() { boolean test(AlbumObject ao) {  ao.getCategory() == Category.image; } } )
 .forEach(new Consumer() {
  void accept(AlbumObject ao) {
     System.out.println(ao.getVars().get("originalDate"));
  }
});
JeffTucker

Posts: 8,039
Registered: 31-Jan-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 21:52   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
davidekholm wrote:
Most developers will probably appreciate the simplistic syntax.

Yes, because most developers are... wait for it... poor simple creatures. ;)

("Simplistic" has an interesting "flavor" in English. It's somewhat akin to "simple-minded" or "dim.")
davidekholm

Posts: 3,442
Registered: 18-Oct-2002
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 21:54   in response to: JeffTucker in response to: JeffTucker
  Click to reply to this thread Reply
jGromit wrote:
davidekholm wrote:
Most developers will probably appreciate the simplistic syntax.

Yes, because most developers are... wait for it... poor simple creatures. ;)

("Simplistic" has an interesting "flavor" in English. It's somewhat akin to "simple-minded" or "dim.")


Ah, adjusted.
JeffTucker

Posts: 8,039
Registered: 31-Jan-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 21:57   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
No, I like the original text. Closer to the truth.
JeffTucker

Posts: 8,039
Registered: 31-Jan-2006
Re: Keyword Labels Maxing at 30
Posted: 14 Aug 17, 22:13   in response to: davidekholm in response to: davidekholm
  Click to reply to this thread Reply
davidekholm wrote:
If you want to use these callback methods in BeanShell you have to resort to using anonymous inner classes....

... which might wipe out the time saving. BeanShell's handling of anonymous inner classes is awful.

In a single-use case like this you might not run into any problems. But if you make extensive use of anonymous inner classes in onload.bsh, for example, skin loading takes forever. This is something TomCee and I discovered many years ago, when I started cleaning up the Matrix UI. Compiled? No problem. Interpreted BeanShell with anonymous inner classes? Skin loading was running over 30 seconds.
Legend
Forum admins
Helpful Answer
Correct Answer

Point your RSS reader here for a feed of the latest messages in all forums