備忘録として、いくつかの実装例を記載しておく。
Hibernate ORMのソート(Spring Data JPAを使用する)
Spring Bootを使用していなくても、下記のように依存関係を読み込むことでSpring Data JPAを使用できる。
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>${spring-data.version}</version>
</dependency>
クエリメソッドを使用する
ルールに沿ったメソッド名を使用することにより、自動的にHibernateへSQLが発行される。
public interface CrudRepository<T, ID> extends Repository<T, ID> {
    // 登録、または更新
    <S extends T> S save(S entity);      
    // プライマリーキーで検索
    Optional<T> findById(ID primaryKey); 
    // 全検索
    Iterable<T> findAll();               
    // 全件数
    long count();                        
    // 削除
    void delete(T entity);               
    // 存在チェック
    boolean existsById(ID primaryKey); 
例えば、小説データを全検索して、小説のタイトルでソートをかけたい場合、下記のように書く。複数のソート条件を指定する場合は続けて記載する。
@Repository
public interface NovelRepository extends JpaRepository<Novel, Long>, JpaSpecificationExecutor<Novel> {
    List<Novel> findAllByOrderByTitle();
}
※「findAll」の後に余分な「By」があるのは、ルール的にそこに検索条件が入ることになるため、今回は全検索なので「By」だけが残っている。
条件 APIを使用する
criteria を記述することにより、クエリの where 句を定義している場合、ソートは以下のように定義する。複数のソート条件を指定する場合は引数を追加する。
novelRepository.findAll(spec, JpaSort.by("title"))
@Repository
public interface NovelRepository extends JpaSpecificationExecutor<Novel> {
}
Hibernate Searchのソート
ソートの処理実装前に、エンティティに@KeywordFieldを追記する必要がある。
    /** タイトル */
    @FullTextField(analyzer = "japanese")
    @KeywordField(name = "titleSort", sortable = Sortable.YES)
    private String title;
検索時に上記で定義した名称をソート条件に指定する。
import org.hibernate.search.mapper.orm.Search;
@Service
public class NovelService {
    private final EntityManager entityManager;
    @Transactional
    public List<Novel> findAllIndex() {
        return Search.session(entityManager)
                .search(Novel.class)
                .where(f -> f.matchAll())
                .sort(f -> f.field("titleSort"))
                .fetchAllHits();
    }
ソートの条件を指定していないときは、スコアの高い順にソートされている。大雑把に言えば、スコアが高いほど、より多くの述語にマッチしているか、より良くマッチしていることを意味する。そのため、Hibernate Searchに関しては明示的にソートの条件を指定しない方が、良いのかもしれない。













