Performance tip: search:tags[] instead of tag[]

Many of my TiddlyWiki projects work with very large numbers of tiddlers that must be filtered quickly through custom search interfaces. Some only have a few thousand items, and others have tens of thousands of items. For collections these large, refresh performance becomes a major concern when the lists of these items (i.e. search results) must update.

I made a post a while ago about a specific performance trick I learned, which was to avoid using the filter Operator when it isn’t necessary. I’ve since discovered more tricks for achieving high performance that I haven’t seen documented or discussed elsewhere, and they’re surprisingly simple.


The biggest one is that search:tags[] is significantly faster than tag[]. I do not have the technical expertise to know why it’s faster, but it’s easily the most useful one for how simple it is. Even when using limit[] to cut down the number of displayed results, (such as for pagination), the difference can be astronomical when working with large lists, especially those that must be filtered down by multiple tags.

For an example of how ridiculous this optimization can be: in my largest searchable collection project BlinkieWiki, it accumulated some major issues with lag when searching by blinkies and by specific colors, since there were a large number of tiddlers in these categories and the filter expression to process search results previously used tag[]. But simply by changing these to search:tags[], the laggiest possible search query (blue blinkies, took 13-15 seconds to process navigating to the next page!) was cut down to around 550 milliseconds. Whew!


A related trick is to use as few filter steps of search:tags[] as possible. The fewer the steps, the quicker the refresh speed (generally speaking). You can combine similar statements into one filter step if they are of the same kind:

  1. Match all tags: search:tags:words[a b c] > search:tags[a]search:tags[b]search:tags[c]
  2. Match no tags: !search:tags:some[a b c] > !search:tags[a]!search:tags[b]!search:tags[c]
  3. Match any tags: search:tags:some[a b c] > [search:tags[a]] :or[search:tags[b]] :or[search:tags[c]] >

The difference is more noticeable when the number of tags that must be filtered is large in addition to the input list being large.

This effect also applies to search:tags[]; the larger the collection, the bigger the difference is between the optimal and suboptimal arrangements. It makes these tricks invaluable for very large wikis to function at reasonable speeds and to stay functional as they scale upward by orders of magnitude.


Lastly, although not that special of a tip, be wary of using redundant or unnecessary filter steps with searching by tags. I discovered a stray unnecessary tag[img] (which wholly overlaps with all tiddlers tagged as “webgraphic”) in a dropdown present in the search interface tiddler. Removing tag[img] in that filter expression eliminated half of the lag caused by that interface.


I’m always in pursuit of pushing the performance speed of TiddlyWiki to its limit, partly out of necessity and partly as the next horizon of my skills to improve on. I’m curious if anyone else has any performance tips in regards to processing large lists. I’ve slowly been developing my first-ever plugin for standardizing the creation of searchable collections, and it takes advantage of as many tricks as possible to keep the refresh speeds snappy.

5 Likes

Seem to be a bug, my claude agent is on the way to find it.

This is when I’ve realized Discourse lacks a facepalm emoji option to tag a post :man_facepalming:

@linonetwo, did you find any explanation for this behavior? I don’t understand the TW backend well enough to investigate it myself, but @MaxDimo‘s observations don’t seem to line up with the general guidance around filter optimization. Surely an indexed filter operator like tag should be more efficient than search, not less?

1 Like

I think I already fixed that, just some bug.

So am I, but that is not difficult for me + AI. Opensource has benefit on this, they have read the source code in training time.

I am pretty sure, that’s not the case. tag[something] is indexed. So the initial run can take longer, when the cache is created. O(N * T) N is number of tiddlers. T is average number of tags per tiddler. The next run should be a O(1) lookup from the cache.

search:tags[x] does a run over all tiddlers, every time it is used. O(N * T * R) R … cost of 1 regexp.

So IMO it is important to see the rest of your filter string and the list-widget, wich uses it.

If we can replicate that, it definitely is a bug. tag[x] should be significantly faster, once initialised.

What’s the workflow, that creates the slow response?

I did create a GH issue: [Report] User claims; `search:tags[]` is faster than `tag[]` · Issue #9837 · TiddlyWiki/TiddlyWiki5 · GitHub

2 Likes

Whoops… I never considered this might be a bug!

I have a number of projects on my plate, but this issue has raised my curiosity to examine this further. BlinkieWiki is a bit convoluted in implementation of this method, so when I have the time for it, I’ll be making a separate wiki with a simpler version of what BlinkieWiki uses with both tag and search:tags to truly test the difference between the two on arbitrary tiddlers. I’m fairly confident I have noticed the difference in all my projects I’ve applied this to, but it wouldn’t hurt to isolate it just to be absolutely sure whether my observations are accurate. I’ll get back to you on this when I have this created.

This is what I discovered when making a 30,000 entry dictionary for Esperanto.

But it might be that searching for a small number of tags inside a large population will work fast, but extracting a large number of tagged items (like 80%) will be slow. Or at least that’s how I understood the “optimisation” at the time. Without this hack, the database would have been unusable.

1 Like

That’s really interesting. For us both to have independently discovered this hack, it’s more likely that the bug is real.

If the number of tags makes a difference in the speed, this would make sense why it’s generally worked in my projects, as they tend to have few tags that need filtering in the search interface. BlinkieWiki especially does not have many, only for the type of graphic and the colors that are present.

I can definitely confirm that lag increases for each additional tag that’s being searched with this method, if they are separate filter statements (i.e. search:tags[a]search:tags[b]search:tags[c]), and if there are many tags it can hinder the refresh speed to an unusable degree. I discovered while bugtesting this issue on a different wiki some time ago that combining them into one filter statement (search:tags:words[a b c]) dramatically improved refresh speeds - but as my friend recently pointed out, this only works for tags that do not have whitespace in their names. The method is effective, but brittle.