JPAによる簡単なタグ付けの実装
1概要
タグ付けは、データモデル内の項目を分類してフィルタ処理することを可能にする標準的なデザインパターンです。
この記事では、SpringとJPAを使用してタグ付けを実装します。私たちはSpring Dataを使ってその仕事を成し遂げるでしょう。さらに、この実装はHibernateを使用したい場合に役立ちます。
これは、タグ付けの実装に関するシリーズの2番目の記事です。 Elasticsearchでそれを実装する方法を見るには、
ここ
を参照してください。
2タグを追加する
-
最初に、タグ付けの最も直接的な実装である文字列のリストを調べます。** エンティティに新しいフィールドを追加してタグを実装できます。
@Entity
public class Student {
//...
@ElementCollection
private List<String> tags = new ArrayList<>();
//...
}
新しいフィールドで
ElementCollection
アノテーションが使用されていることに注目してください。
データストアの前で実行しているので、タグの保存方法を指示する必要があります。
注釈を追加しなかった場合、それらは1つのBLOBに格納されるため、操作が難しくなります。このアノテーションは
STUDENT
TAGS
(つまり
<entity>
<field>
)と呼ばれる別のテーブルを作成します。
-
これにより、エンティティとタグの間に一対多の関係が作成されます!** ここでは、最も単純なバージョンのタグ付けを実装しています。このため、私たちは潜在的にたくさんの重複したタグを持つことになるでしょう(それを持っているエンティティごとに一つ)。この概念については後で詳しく説明します。
3ビルディングクエリ
タグを使用すると、データに対して興味深いクエリをいくつか実行できます。特定のタグを持つエンティティを検索したり、テーブルスキャンをフィルタリングしたり、特定のクエリで返される結果を制限したりすることもできます。それぞれのケースを見てみましょう。
3.1. タグを検索する
データモデルに追加した
tag
フィールドは、モデルの他のフィールドと同様に検索できます。クエリを構築するときは、タグを別のテーブルに保存します。
特定のタグを含むエンティティを検索する方法は次のとおりです。
@Query("SELECT s FROM Student s JOIN s.tags t WHERE t = LOWER(:tag)")
List<Student> retrieveByTag(@Param("tag") String tag);
タグは別のテーブルに格納されているため、クエリでそれらを結合する必要があります。これにより、一致するタグを持つすべての
Student
エンティティが返されます。
まず、テストデータをいくつか設定しましょう。
Student student = new Student(0, "Larry");
student.setTags(Arrays.asList("full time", "computer science"));
studentRepository.save(student);
Student student2 = new Student(1, "Curly");
student2.setTags(Arrays.asList("part time", "rocket science"));
studentRepository.save(student2);
Student student3 = new Student(2, "Moe");
student3.setTags(Arrays.asList("full time", "philosophy"));
studentRepository.save(student3);
Student student4 = new Student(3, "Shemp");
student4.setTags(Arrays.asList("part time", "mathematics"));
studentRepository.save(student4);
次に、それをテストし、それが機能することを確認しましょう:
----//Grab only the first result
Student student2 = studentRepository.retrieveByTag("full time").get(0);
assertEquals("name incorrect", "Larry", student2.getName());
----
full time
タグを付けて、リポジトリの最初の生徒を元に戻します。これこそまさに私たちが望んでいたことです。
さらに、この例を拡張して、より大きなデータセットをフィルタ処理する方法を示すことができます。これがその例です。
List<Student> students = studentRepository.retrieveByTag("full time");
assertEquals("size incorrect", 2, students.size());
少しリファクタリングするだけで、リポジトリを変更してフィルタとして複数のタグを取り込むことができるので、結果をさらに絞り込むことができます。
3.2. クエリのフィルタリング
私たちの単純なタグ付けのもう一つの有用な応用は特定の問い合わせにフィルタを適用することです。前の例でもフィルタリングを行うことができましたが、テーブルのすべてのデータを処理しました。
他の検索もフィルタリングする必要があるので、例を見てみましょう。
@Query("SELECT s FROM Student s JOIN s.tags t WHERE s.name = LOWER(:name) AND t = LOWER(:tag)")
List<Student> retrieveByNameFilterByTag(@Param("name") String name, @Param("tag") String tag);
このクエリは上記のものとほぼ同じであることがわかります。
tag
は、このクエリで使用する別の制約にすぎません。
私たちの使用例もお馴染みになるでしょう:
Student student2 = studentRepository.retrieveByNameFilterByTag(
"Moe", "full time").get(0);
assertEquals("name incorrect", "moe", student2.getName());
その結果、このエンティティの任意のクエリにタグ
filter
を適用できます。
これにより、ユーザーは必要なデータを正確に見つけることができます。
4高度なタグ付け
-
私たちの単純なタグ付けの実装は、始めるのに最適な場所です。しかし、一対多の関係のために、いくつかの問題に出くわすことができます。
まず、重複したタグでいっぱいのテーブルになります。これは小規模なプロジェクトでは問題になりませんが、大規模なシステムでは何百万件(場合によっては数十億も)の重複エントリが発生する可能性があります。
また、私たちの
Tag
モデルはあまり堅牢ではありません。タグが最初に作成された時期を追跡したい場合はどうしますか?現在の実装では、それを行う方法はありません。
最後に、
tags
を複数のエンティティタイプで共有することはできません。これにより、システムのパフォーマンスに影響を与える可能性がある、さらに重複する可能性があります。
-
多対多の関係は、私たちの問題の大部分を解決するでしょう**
@ manytomany
アノテーションの使い方を学ぶためには、リンクをチェックしてください:/hibernate-many-to-many[この記事]この記事)。
5結論
タグ付けは、データをクエリできるようにするためのシンプルで直接的な方法であり、Java Persistence APIと組み合わせることで、簡単に実装できる強力なフィルタリング機能が得られます。
単純な実装が常に最も適しているとは限りませんが、そのような状況を解決するために取るべきルートを強調しました。
いつものように、この記事で使われているコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-jpa[over on GitHub]にあります。
次
”
-
«** 前へ