Perhaps I'm missing something, but couldn't you do something like this in a saveReady hook?
$pages->addHookAfter('saveReady', function(HookEvent $event) {
$page = $event->arguments(0);
if($page->template == 'book') {
$page->my_sort_field = implode(' ', array_filter([
$page->subject,
$page->cleanauthor,
$page->cleantitle,
]));
}
});
... and now that your sort field (which could be a hidden text field, or a textarea if there's a lot of data, which I assume is not the case) contains a single value, you can sort results by that. As far as I can tell the only issue here is that you'll basically have the same data stored multiple times ?♂️
(Unless I've misunderstood you, and you actually want to keep all books that have a subject before any of those that don't, etc. But in that case a simple sort by multiple field seems enough.)