Acabei resolvendo com uma subconsulta correlacionada:
$qb
->select('a')
->from('Article', 'a')
->join('a.views', 'v')
->orderBy('v.viewDate', 'DESC')
->setMaxResults(20)
// Only select the most recent article view for each individual article
->where('v.viewDate = (SELECT MAX(v2.viewDate) FROM ArticleView v2 WHERE v2.article = a)')
Dessa forma, a classificação ignora os ArticleView que não sejam os mais recentes para qualquer artigo. Embora meu palpite seja que isso tenha um desempenho bastante ruim em relação às outras soluções SQL brutas - quaisquer respostas com melhor desempenho ainda seriam muito apreciadas :).