That's a tricky query - and I'm not even sure it would work in general. Even if you try running the raw SQL query with DB::select($query) I think you may run into trouble.
It may be dependent on the MySQLServer settting for sql_mode=only_full_group_by being off, which is not really portable. I'm not 100% sure about this, but it doesn't seem to work for me, so I'll leave it at that.
I do have an eloquent solution for you though. It's not perfect as the main query actually pulls all of the News items (which you could limit in some way, maybe ->whereBetween('published_at',...)), but here is what I would do:
$topics = [];
$news = News::where('state', 'published_at')
->where('published_at', '<=', now())
->whereFeatured(1)
->orderByDesc('published_at')
->get()
->filter(function ($v) use (&$topics) {
$found = in_array($v->topic, $topics);
$topics[] = $v->topic;
return !$found;
})
->take(3)
;