I think there are a number of options, depending on priorities. My understanding of you requirement is that the JSON displays content from other pages, not just from the page in the URL right? If so then you are limited to solutions that are either TTL or dependency based (other than the auto-invalidation).
One of the things you could do is theory if you have a tolerance for somewhat stale content you could implement a crawler that would remove any cached JSON (or change the stat file to cause dispatcher to think this is invalid) whose mod date is older X minutes or hours. Depending on the size of your site this may or may not be viable.
You could also add a unique selector and use that for your auto-invalidation logic - that way only this list's json is auto-invalidated not other json files.
You could also implement a custom replication agent that was aware of dependency logic of your component and issues additonal cache flush commands for the JSON objects that need to be removed. This may or may not be possible based on the logic of your list components. This is not an insignifcant customization.
There are options to make the auto-invalidation more granular (by reducing the stat file level) which may or not be viable for you.
On the one hand side you can cache on dispatcher. But this might cause some headache, as you see :-) Orotas already gave you a number of very valuable hints how you could make it.
On the other hand: You could hold you search results in a cache on publish and update the cache via JCR observation: Whenever a relevant page is changed, it is reflected immediately in your cache. Then you don't need to do your expensive Query on every request.
I am actually exploring caching on publisher option, is there a prefered way to cache on publisher (in terms of library)? In normal Java Web applications I used Servlet Context and EH Cache.
The product itself does not deliver any library with it. So adding EhCache would be ok.
So build a service, which controls this cache and also is notified by JCR observation if any changes happen. I would not fiddle with Servlet Context or something like this. From a page you can then query that service for the expected result. The service fetches them out of the cache.