Saya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:
>> LIHAT KURSUS Artikel ini adalah sebahagian daripada siri: • Pelaksanaan Penandaan Ringkas dengan Elasticsearch (artikel semasa) • Pelaksanaan Penandaan Ringkas dengan JPA• Pelaksanaan Penandaan Lanjutan dengan JPA
• Pelaksanaan Penandaan Ringkas dengan MongoDB
1. Gambaran keseluruhan
Penandaan adalah corak reka bentuk umum yang membolehkan kita mengkategorikan dan menyaring item dalam model data kita.
Dalam artikel ini, kami akan menerapkan penandaan menggunakan Spring dan Elasticsearch. Kami akan menggunakan Spring Data dan Elasticsearch API.
Pertama sekali, kami tidak akan membahas asas mendapatkan Elasticsearch dan Spring Data - anda boleh menerangkannya di sini.
2. Menambah Tag
Pelaksanaan penandaan paling mudah adalah pelbagai rentetan. Kami dapat melaksanakannya dengan menambahkan bidang baru pada model data kami seperti ini:
@Document(indexName = "blog", type = "article") public class Article { // ... @Field(type = Keyword) private String[] tags; // ... }
Perhatikan penggunaan jenis medan Kata Kunci . Kami hanya mahukan padanan teg kami yang tepat untuk menapis hasilnya. Ini membolehkan kita menggunakan teg yang serupa tetapi terpisah seperti elasticsearchIsAwesome dan elasticsearchIsTerrible .
Medan yang dianalisis akan menghasilkan hits separa yang merupakan kelakuan yang salah dalam kes ini.
3. Pertanyaan Membina
Teg membolehkan kami memanipulasi pertanyaan kami dengan cara yang menarik. Kita boleh mencari di seberang seperti bidang lain, atau kita boleh menggunakannya untuk menyaring hasil kita pada pertanyaan match_all . Kami juga dapat menggunakannya dengan pertanyaan lain untuk memperketat hasil kami.
3.1. Mencari Tag
Medan tag baru yang kami buat pada model kami sama seperti bidang lain dalam indeks kami. Kita boleh mencari mana-mana entiti yang mempunyai tag tertentu seperti ini:
@Query("{\"bool\": {\"must\": [{\"match\": {\"tags\": \"?0\"}}]}}") Page findByTagUsingDeclaredQuery(String tag, Pageable pageable);
Contoh ini menggunakan Spring Data Repository untuk membina pertanyaan kami, tetapi kami dapat dengan cepat menggunakan Templat Rehat untuk menanyakan kluster Elasticsearch secara manual.
Begitu juga, kita boleh menggunakan Elasticsearch API:
boolQuery().must(termQuery("tags", "elasticsearch"));
Andaikan kami menggunakan dokumen berikut dalam indeks kami:
[ { "id": 1, "title": "Spring Data Elasticsearch", "authors": [ { "name": "John Doe" }, { "name": "John Smith" } ], "tags": [ "elasticsearch", "spring data" ] }, { "id": 2, "title": "Search engines", "authors": [ { "name": "John Doe" } ], "tags": [ "search engines", "tutorial" ] }, { "id": 3, "title": "Second Article About Elasticsearch", "authors": [ { "name": "John Smith" } ], "tags": [ "elasticsearch", "spring data" ] }, { "id": 4, "title": "Elasticsearch Tutorial", "authors": [ { "name": "John Doe" } ], "tags": [ "elasticsearch" ] }, ]
Sekarang kita boleh menggunakan pertanyaan ini:
Page articleByTags = articleService.findByTagUsingDeclaredQuery("elasticsearch", PageRequest.of(0, 10)); // articleByTags will contain 3 articles [ 1, 3, 4] assertThat(articleByTags, containsInAnyOrder( hasProperty("id", is(1)), hasProperty("id", is(3)), hasProperty("id", is(4))) );
3.2. Menapis Semua Dokumen
Corak reka bentuk yang biasa adalah membuat Tampilan Senarai yang Disaring di UI yang menunjukkan semua entiti, tetapi juga membolehkan pengguna menyaring berdasarkan kriteria yang berbeza.
Katakanlah kami ingin mengembalikan semua artikel yang disaring dengan teg apa pun yang dipilih pengguna:
@Query("{\"bool\": {\"must\": " + "{\"match_all\": {}}, \"filter\": {\"term\": {\"tags\": \"?0\" }}}}") Page findByFilteredTagQuery(String tag, Pageable pageable);
Sekali lagi, kami menggunakan Spring Data untuk membina pertanyaan yang kami nyatakan.
Akibatnya, pertanyaan yang kami gunakan terbahagi kepada dua bahagian. Pertanyaan pemarkahan adalah istilah pertama, dalam kes ini, match_all . Pertanyaan penapis adalah seterusnya dan memberitahu Elasticsearch yang hasilnya akan dibuang.
Inilah cara kami menggunakan pertanyaan ini:
Page articleByTags = articleService.findByFilteredTagQuery("elasticsearch", PageRequest.of(0, 10)); // articleByTags will contain 3 articles [ 1, 3, 4] assertThat(articleByTags, containsInAnyOrder( hasProperty("id", is(1)), hasProperty("id", is(3)), hasProperty("id", is(4))) );
Penting untuk menyedari bahawa walaupun ini memberikan hasil yang sama seperti contoh kita di atas, pertanyaan ini akan menunjukkan prestasi yang lebih baik.
3.3. Menapis Pertanyaan
Kadang kala carian mengembalikan terlalu banyak hasil untuk dapat digunakan. Sekiranya demikian, ada baiknya mengekspos mekanisme penyaringan yang dapat menjalankan kembali carian yang sama, hanya dengan hasil yang disempit.
Berikut adalah contoh di mana kita menyempitkan artikel yang ditulis oleh pengarang, kepada artikel yang mempunyai teg tertentu:
@Query("{\"bool\": {\"must\": " + "{\"match\": {\"authors.name\": \"?0\"}}, " + "\"filter\": {\"term\": {\"tags\": \"?1\" }}}}") Page findByAuthorsNameAndFilteredTagQuery( String name, String tag, Pageable pageable);
Sekali lagi, Spring Data melakukan semua pekerjaan untuk kita.
Mari kita lihat bagaimana membina pertanyaan ini sendiri:
QueryBuilder builder = boolQuery().must( nestedQuery("authors", boolQuery().must(termQuery("authors.name", "doe")), ScoreMode.None)) .filter(termQuery("tags", "elasticsearch"));
Kita tentu saja dapat menggunakan teknik yang sama untuk menyaring bidang lain dalam dokumen. Tetapi tag sangat sesuai dengan kes penggunaan ini.
Inilah cara menggunakan pertanyaan di atas:
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder) .build(); List articles = elasticsearchTemplate.queryForList(searchQuery, Article.class); // articles contains [ 1, 4 ] assertThat(articleByTags, containsInAnyOrder( hasProperty("id", is(1)), hasProperty("id", is(4))) );
4. Konteks Tapisan
Semasa kita membuat pertanyaan, kita perlu membezakan antara Konteks Pertanyaan dan Konteks Saringan. Setiap pertanyaan di Elasticsearch mempunyai Konteks Pertanyaan sehingga kita harus terbiasa melihatnya.
Not every query type supports the Filter Context. Therefore if we want to filter on tags, we need to know which query types we can use.
The bool query has two ways to access the Filter Context. The first parameter, filter, is the one we use above. We can also use a must_not parameter to activate the context.
The next query type we can filter is constant_score. This is useful when uu want to replace the Query Context with the results of the Filter and assign each result the same score.
The final query type that we can filter based on tags is the filter aggregation. This allows us to create aggregation groups based on the results of our filter. In other words, we can group all articles by tag in our aggregation result.
5. Advanced Tagging
So far, we have only talked about tagging using the most basic implementation. The next logical step is to create tags that are themselves key-value pairs. This would allow us to get even fancier with our queries and filters.
For example, we could change our tag field into this:
@Field(type = Nested) private List tags;
Then we'd just change our filters to use nestedQuery types.
Setelah kita memahami bagaimana menggunakan pasangan nilai-kunci, ini adalah langkah kecil untuk menggunakan objek yang kompleks sebagai tag kita. Tidak banyak pelaksanaan yang memerlukan objek penuh sebagai tag, tetapi ada baiknya kita mengetahui bahawa kita mempunyai pilihan ini sekiranya kita memerlukannya.
6. Kesimpulannya
Dalam artikel ini, kami telah membahas asas-asas pelaksanaan penandaan menggunakan Elasticsearch.
Seperti biasa, contoh boleh didapati di GitHub.
Seterusnya » Pelaksanaan Penandaan Ringkas dengan Ketekunan JPA di bawah