美文网首页
Elasticsearch 整合 Spring Boot(2)

Elasticsearch 整合 Spring Boot(2)

作者: SheHuan | 来源:发表于2020-12-20 21:40 被阅读0次

    在上一篇中我们已经准备好了数据,接下来就是创建索引、将数据添加到索引中了。

    Elasticsearch 使用 Java High Level REST Client 操作索引、文档中,我们引入了 Spring Data Elasticsearch 的依赖,这样我们就可以利用 Spring Data 的一些特性来简化 ES 的操作。

    先贴一下参考官方文档 Spring Data Elasticsearch - Reference Documentation

    1、连接 ES

    整合 Spring Boot 后,我们连接 ES 节点的方式就很简单了,只需要在application.properties添加各个节点的 http 地址,多个地址用英文逗号隔开:

    spring.elasticsearch.rest.uris=http://127.0.0.1:9200,http://127.0.0.1:9201,http://127.0.0.1:9202
    

    2、创建文档数据实体类

    前边我们将采集到的的数据保存成了 JSON 格式,结构如下:


    我们先要创建 JSON 数据对应的实体类Book

    @Document(indexName = "book")
    public class Book {
        private String id;
    
        @Field(type = FieldType.Keyword)
        private String skuId;
    
        @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
        private String name;
    
        @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
        private String author;
    
        private Float price;
    
        @Field(type = FieldType.Integer)
        private Integer commentCount;
    
        @Field(type = FieldType.Text, analyzer = "ik_max_word")
        private String shop;
    
        @Field(type = FieldType.Text, analyzer = "ik_max_word")
        private String publisher;
    
        @Field(type = FieldType.Text)
        private String img;
    
        ...省略get\set方法...
    }
    

    @Document标记该类对应索引库中的文档信息,同时指定了索引库的名字为book,还可以指定分片数量;类里边的id属性是必需的,对应文档 id;类里边其它属性上的@Field注解相当于定义了文档中各个字段的类型、分词。

    3、创建索引、添加文档数据

    3.1、ElasticsearchRepository

    3.1.1、创建索引

    使用 Spring Data 的特性,创建BookRepository,继承ElasticsearchRepository,泛型参数Book就是上边的实体类,String则是文档 id 的类型:

    public interface BookRepository extends ElasticsearchRepository<Book, String> {
    }
    

    完成上边的工作后,启动项目,会自动帮我们创建好索引库。

    3.1.2、添加文档

    创建好了索引库,就可以添加文档了。

    创建一个BookService类,通过addBook()方法来批量添加文档数据:

    @Service
    public class BookService {
        @Autowired
        BookRepository bookRepository;
    
        public void addBook(List<Book> books) {
            elasticsearchRestTemplate.save(books);
        }
    }
    

    由于我们采集到的数据事先保存在了文件中,所以需要从文件中读取数据,在调用上边的addBook()来添加:

    @Service
    public class BookFileService {
        @Autowired
        BookService bookService;
    
        /**
         * 将去重后的数据写入 ES
         */
        public void writeBookDataToES() {
            String filePath = System.getProperty("user.dir") + File.separator + "jd_book2.txt";
    
            FileReader fileReader = null;
            BufferedReader bufferedReader = null;
            try {
                fileReader = new FileReader(filePath);
                bufferedReader = new BufferedReader(fileReader);
                String line;
                ArrayList<Book> books = new ArrayList<>();
                while ((line = bufferedReader.readLine()) != null) {
                    books.add(JSON.parseObject(line, Book.class));
                    if (books.size() >= 500) {
                        // 添加数据到 ES
                        bookService.addBook(books);
                        books.clear();
                    }
                }
                bookService.addBook(books);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                ......
            }
        }
    }
    

    代码比较简单,就是逐行读取文件,然后批量添加即可。

    最后执行writeBookDataToES()方法即可完成添加,速度还是很快的,基本10秒左右就完成了:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    class LearnElasticsearchApplicationTests {
    
        @Autowired
        BookFileService bookFileService;
    
        @Test
        void testES() throws IOException {
            bookFileService.writeBookDataToES();
        }
    }
    

    最后可以在 head 工具中浏览添加好的数据。

    前边我们通过继承ElasticsearchRepository,扩展了BookRepository类,利用 Spring Data Repository 的特性,不需要再编写额外的代码,使用BookRepository就可以完成文档的添加、删除、查询等操作。遵照按照 Spring Data 的规范,我们还可以根据需要来扩展其它的方法来操作文档。如果你之前用过 Spring Data JPA,那么这个就很容易理解了。

    3.2、ElasticsearchRestTemplate

    ElasticsearchRestTemplate相当于一个 ES 客户端,它的内部基于 Java High Level REST Client 实现的。你可能还见过ElasticsearchTemplate,但是从 Spring Data 4.0开始已经过时了,目前推荐使用 ElasticsearchRestTemplate。

    相比 ElasticsearchRepository 它的功能更丰富一些、效率更高,而且不用和数据体类绑定,使用 ElasticsearchRestTemplate 除了可以操作文档,还可以操作索引。

    我们重点要学习的就是 ElasticsearchRestTemplate,它的主要功能通过如下三个接口定义的:

    • IndexOperations,定义索引相关的操作,例如创建、删除索引。
    • DocumentOperations,定义文档相关的操作,例如添加、删除、更新、基于文档 id 的简单查询。
    • SearchOperations,定义各种文档查询的操作。

    3.2.1、创建索引

    前边是通过定义BookRepository来实现索引的自动创建,其实有了ElasticsearchRestTemplate,我们可以完全不使用 Spring Data Repository 相关的扩展类,注释掉BookRepository,我们现在使用 ElasticsearchRestTemplate 来创建索引:

    @Service
    public class BookService {
    
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        public void createIndex() {
            // 指定文档的数据实体类
            IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);
            // 创建索引
            indexOperations.create();
            // 创建字段映射
            Document mapping = indexOperations.createMapping();
            // 给索引设置字段映射
            indexOperations.putMapping(mapping);
        }
    }
    

    删除索引就简单了,顺便说一下:

    public void deleteIndex() {
        IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Book.class);
        boolean result = indexOperations.delete();
        System.out.println(result);
    }
    

    3.2.2、添加文档

    首先我们可以使用 ElasticsearchRestTemplatesave()方法添加文档:

    @Service
    public class BookService {
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        public void addBook(List<Book> books) {
            elasticsearchRestTemplate.save(books);
        }
    }
    

    除了save()方法,我们还可以使用bulkIndex()方法,它是一次批量添加数据的,而save()是逐个添加。来看如何使用bulkIndex()方法:

    @Service
    public class BookService {
    
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        public void bulkAddBook(List<Book> books) {
            List<IndexQuery> indexQueryList = new ArrayList<>();
            books.forEach(book -> {
                IndexQuery indexQuery = new IndexQuery();
                indexQuery.setObject(book);
                indexQueryList.add(indexQuery);
            });
    
            elasticsearchRestTemplate.bulkIndex(indexQueryList, IndexCoordinates.of("book"));
        }
    }
    

    主要是通过IndexQuerysetObject()方法设置要添加的数据,bulkIndex()方法第二个参数用来指定索引信息。

    如果需要的话可以使用IndexQuerysetId()方法来设置文档 id。

    我的采集到的数据是以 JSON 格式保存在文件中,能否直接添加 JSON 数据呢,而不是转换成实体类的对象再添加。这个需求我们同样可以用bulkIndex()来完成:

    @Service
    public class BookService {
    
        @Autowired
        ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        public void bulkAddBook2(List<String> books) {
            List<IndexQuery> indexQueryList = new ArrayList<>();
            books.forEach(book -> {
                IndexQuery indexQuery = new IndexQuery();
                indexQuery.setSource(book);
                indexQueryList.add(indexQuery);
            });
    
            elasticsearchRestTemplate.bulkIndex(indexQueryList, IndexCoordinates.of("book"));
        }
    }
    

    其实就是通过IndexQuerysetSource()方法设置要添加的原始 JSON 数据。

    这样从文件读取的数据就可以直接添加了:

    public void writeBookDataToES2() {
        ......
        try {
            fileReader = new FileReader(filePath);
            bufferedReader = new BufferedReader(fileReader);
            String line;
            ArrayList<String> books = new ArrayList<>();
            while ((line = bufferedReader.readLine()) != null) {
                books.add(line);
                if (books.size() >= 500) {
                    bookService.bulkAddBook2(books);
                    books.clear();
                }
            }
            bookService.bulkAddBook2(books);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            ......
        }
    }
    

    注意,使用ElasticsearchRestTemplatesave()或者bulkIndex()方法添加文档时,如果添加了相同文档 id 的数据,则之前的会被覆盖掉。如果是使用ElasticsearchRepositorysave()方法,则无法正常添加。

    本文详细的代码可以参考:https://github.com/SheHuan/LearnElasticsearch

    相关文章

      网友评论

          本文标题:Elasticsearch 整合 Spring Boot(2)

          本文链接:https://www.haomeiwen.com/subject/txnbbktx.html