Ancestors and descendants filter operators

Some of the feedback for the Recursive filter operators to show all tiddlers beneath a tag and all tags above a tiddler was the request to be able to use fields other than tags to connect tiddlers. After some reworking, these are the results:

Both allow to define an optional field to use, as well as to optionally limit the number of hierarchy levels to traverse. By default, tags is used with unlimited recursion, yielding identical results to tagstree and taggingtree.

For speed comparison, here is a quite extreme example (a wiki with 8,500 tiddlers out of which ā‰ˆ 3,600 are descendants of the base tiddler Origin via tags):

Filter Median time Uses Total time Total time (last 10) Longest run Average time
[[Origin]kin:tags:to[]count[]] 7336.50ms 10 73235.00ms 73235.00ms 7386.00ms 7323.50ms
[[Origin]descendants[]count[]] 11.50ms 10 114.00ms 114.00ms 14.00ms 11.40ms

Yes, descendants is 600Ɨ faster here. The difference will be much less for smaller wikis and fewer results and recursion levels, though. Also, using fields other than tags with ancestors and descendants will also be somewhat slower.

Let me know if you run into any problems.

Yaisog

7 Likes

Thanks @Yaisog! I can also confirm it works as expected (order) - thanks again!

Just for your knowledge, for my use case (kin:list:from[] vs. ancestors[list]prepend[root]) Iā€™m now getting almost the same time in my 900 tiddler test, so Iā€™m guessing most of the speed improvement is on the tags side and/or in the other direction (descendant vs. kin:tags:to). I have a feeling the loop protection and sort order recently added mightā€™ve slightly slowed things down a bit for my use case.

Useful alternatives though! :slight_smile:

I have a simple ToC hierarchy and I try to use ancestors filter in the leaf tiddler. If it has multiple tags, they show up in the hierarchy chain.

Instead of Level2 -> Level1 -> root -> +mytag -> I want just Level2 -> Level1 -> root -> since root is the node containing the ToC.

I thought it could be a problem because of the + prefix, but if I replace +mytag with just mytag, I get the same results.

JSON dump of tiddlers is attached below.

tiddlers.json (722 Bytes)

That is the purpose of this filter.

To be honest I am not quite sure that I understand your problem. If you just want to remove +mytag from the results, you could use the Except Filter Run Prefix:

[[Level 3]ancestors[]] :except[[+mytag]]

Also, personally, I would avoid using a + as the first character in a tag name, because itā€™s visually so similar to the shortcut for the :and filter run prefix which would appear at the beginning of filter runs. That can make code unnecessarily hard to read.

I might be misunderstanding how the filter works:

  • Ancestors are all tiddlers that are tags of the input tiddlers (i.e. their parents), all tiddlers that are tags of the parents (i.e. their grandparents), and so forth.

Emphasis mine.

In my example above: I create root tiddler, Level1 tiddler with root tag, Level2 tiddler with Level1 tag, Level3 tiddler with Level2 tag. I get the whole hierarchy when using [[Level3]ancestors[]] - thatā€™s fine. But I donā€™t get why I get other tags of Level3 if there are more tags as well. Sure, +mytag is a tag of Level3 (see the quoted definition above), yet thereā€™s no +mytag tiddler (again, see the quoted definition above).

Of course in ToC hierarchies the concepts of tiddlers and tags get intermixed, maybe this is the root of my misunderstanding?

I am trying to use ancestors[] to collect a chain from a tiddler back to the root in a hierarchy tree, in the example above +mytag is not involved in creating the hierarchy structure at all.

Also, I donā€™t understand how can I use your example above and hardcode the exception: this is a chopped minimal example, my tiddlers can have multiple tags and I donā€™t know which ones to exclude, because I donā€™t know which tag is involved in building the hierarchy, unless I would explicitly check for that, as in iterate over all tags, see which one matches against the title of another existing tiddler.

The ancestors filter simply collects all tags, whether they exist as tiddlers or not. I might need to change the wording on the description. In my mind, tags always exist as tiddlers, but I see that this doesnā€™t have to be the case.

What you want is probably

[[Level 3]ancestors[]is[tiddler]]

This would remove any tags that donā€™t exist as tiddlers, in your case +mytag. Or,

[[Level 3]ancestors[]!prefix[+]

This would remove any items that start with a +, if that is your notation for non-hierarchy tags. You can always remove the elements that you donā€™t want to see from the output of the ancestors filter with subsequent filters.

1 Like

IIRC both the official docs and GrokTiddlyWiki explain that tags can be tiddlers (as opposite to just strings), but they donā€™t have to. And TiddlyWiki does not automatically create a tiddler for each created tag.

I am not necessarily implying that the documentation for ancestors filter is confusing (since Iā€™m not a native English speaker), but having these things stated explicitly and a more emphasized difference between tags and tiddlers shall definitely help creating a clearer mental model.

I always think ā€œin tiddlersā€ rather than ā€œin tagsā€ in context of filters, I guess this is why I was surprised to see tags in the output of ancestors filter.