6.4spring整合elastic search

Insert picture description here


Insert picture description here

Next, we need to modify the bottom layer, the part of the NettyRuntime class (that is, set the available processors)

Insert picture description here
 "availableProcessors is already set to [%d], rejecting [%d]",

Translation: availableProcessors has been set up.

This error will be reported because redis and elastic search are both based on Netty, so it will cause conflicts at the bottom, so an error will be reported.
The conflict is mainly reflected in the es code. The setAvailableProcessors method is called by es. In the Netty4Utils class (a class encapsulated by the es bottom layer), the
code is as follows:

Insert picture description here


In order to set up, add in the community application

@PostConstruct//管理bean声明周期的注解
public void init() {
    // 解决netty启动冲突问题
    // see Netty4Utils.setAvailableProcessors()
    System.setProperty("es.set.netty.runtime.available.processors", "false");
}

Then you need to configure.
In discusspost, it was originally like this.

Insert picture description here


Add annotations before each attribute . After

Insert picture description here


adding these annotations to the entity class, a connection is established with es, and each field is established with each field in es. Relationship

Next, define the repository interface.
Create DiscussPostRepository interface in dao

package com.nowcoder.community.dao.elasticsearch;

import com.nowcoder.community.entity.DiscussPost;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

@Repository  //@mapper是mybatis的注解,Repository是spring提供的针对数据访问层的注解
public interface DiscussPostRepository extends ElasticsearchRepository<DiscussPost, Integer> {//接口要处理的实体类DiscussPost,实体类中的组件Integer
//该接口不需要新的,只继承 Elasticsearch即可
}

Create a new test class and
query first. It is found that as long as one index

Insert picture description here


inserts these three pieces of data in mysql,

Insert picture description here
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class ElasticsearchTests {

    @Autowired
    private DiscussPostMapper discussMapper;//注入discussMapper,方便从mysql中取出数据

    @Autowired
    private DiscussPostRepository discussRepository;//方便查数据

    @Autowired
    private ElasticsearchTemplate elasticTemplate;//有些情况ElasticsearchRepository 处理不了,需要ElasticsearchTemplate来处理

    @Test
    public void testInsert() {//往es里插入单条数据
        discussRepository.save(discussMapper.selectDiscussPostById(241));
        discussRepository.save(discussMapper.selectDiscussPostById(242));
        discussRepository.save(discussMapper.selectDiscussPostById(243));
    }

You can find it in:

Insert picture description here


Insert picture description here


Insert picture description here
@Test
public void testInsertList() {//往es里插入多条数据
    discussRepository.saveAll(discussMapper.selectDiscussPosts(101, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(102, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(103, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(111, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(112, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(131, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(132, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(133, 0, 100));
    discussRepository.saveAll(discussMapper.selectDiscussPosts(134, 0, 100));
}

No error was reported
. 141 pieces of data were hit, but not all of them were listed.

Insert picture description here


Test: Change the data.

Insert picture description here


Insert picture description here


Change its content to:

@Test
public void testUpdate() {//修改数据
    DiscussPost post = discussMapper.selectDiscussPostById(231);//被修改的数据
    post.setContent("我是新人,使劲灌水.");
    discussRepository.save(post);
}

Query again:

Insert picture description here


Test delete data

@Test
public void testDelete() {//删除数据
    // discussRepository.deleteById(231);
    discussRepository.deleteAll();删除索有数据
}

Search, the core function of es. es can light up the returned keywords, and the implementation mechanism is to light up the tags

Insert picture description here
  @Test
    public void testSearchByRepository() {//搜索,es最核心的功能。es可以把返回的关键词点亮,实现的机制是把标签点亮
        SearchQuery searchQuery = new NativeSearchQueryBuilder()//spring提供的searchQuery接口
                .withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))//NativeSearchQueryBuilder构建的实现类。withQuery里面是搜索条件。multiMatchQuery是多字段全文的搜索。"互联网寒冬"是搜索内容。
                .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))//构造排序条件。QueryBuilders是查询条件,SortBuilders是排序条件。type=1意味着置顶。status=1意味着加精。DESC是倒序排列,这样=1的会被排在前面
                .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))//状态加精会 算成一个分数,按分数来排序
                .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))//前两个都一样的话,按创造时间排序
                .withPageable(PageRequest.of(0, 10))//从第0页开始,一页最多显示10条数据
                .withHighlightFields(//指定哪些字段高亮显示
                        new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),//title里面,preTags前置标签<em>,后置标签</em>
                        new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
                ).build();//build方法一执行会返回searchQuery

        Page<DiscussPost> page = discussRepository.search(searchQuery);//用Page对象封装 查询到的
        System.out.println(page.getTotalElements());//一共多少个数据匹配,111
        System.out.println(page.getTotalPages());//一共有多少页,12(111条数据,每页显示10条,共有12页)
        System.out.println(page.getNumber());//当前在第几页 0
        System.out.println(page.getSize());//每页最多显示几条数据  10
        for (DiscussPost post : page) {//遍历page
            System.out.println(post);
        }
    }

Result:

Insert picture description here


But there is no em and no highlighting, so add a sentence:

// elasticTemplate.queryForPage(searchQuery, class, SearchResultMapper) 把高亮的数据整合到原始数据中,做个替换才可以。class是哪个类型数据
// elastic底层 调用了此方法获取得到了高亮显示的值, 但是没有返回.

test:

@Test
public void testSearchByTemplate() {//为了能够高亮显示,直接用Template 方法测试
    SearchQuery searchQuery = new NativeSearchQueryBuilder()//searchQuery和之前一模一样 不用动
            .withQuery(QueryBuilders.multiMatchQuery("互联网寒冬", "title", "content"))
            .withSort(SortBuilders.fieldSort("type").order(SortOrder.DESC))
            .withSort(SortBuilders.fieldSort("score").order(SortOrder.DESC))
            .withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
            .withPageable(PageRequest.of(0, 10))
            .withHighlightFields(
                    new HighlightBuilder.Field("title").preTags("<em>").postTags("</em>"),
                    new HighlightBuilder.Field("content").preTags("<em>").postTags("</em>")
            ).build();

    Page<DiscussPost> page = elasticTemplate.queryForPage(searchQuery, DiscussPost.class, new SearchResultMapper() {//设置Query,DiscussPost.class实体类型
        @Override
        public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> aClass, Pageable pageable) {
            SearchHits hits = response.getHits();//得到封装的多条数据
            if (hits.getTotalHits() <= 0) {//说明没查到数据
                return null;
            }

            List<DiscussPost> list = new ArrayList<>();//声明一个集合,集合里面装的是DiscussPost
            for (SearchHit hit : hits) {
                DiscussPost post = new DiscussPost();//实例化 实体类

                String id = hit.getSourceAsMap().get("id").toString();//hit.getSourceAsMap()得到map形式的数据,之后得到id 并转为字符串
                post.setId(Integer.valueOf(id));

                String userId = hit.getSourceAsMap().get("userId").toString();
                post.setUserId(Integer.valueOf(userId));

                String title = hit.getSourceAsMap().get("title").toString();//原始显示的title,而不是高亮显示的
                post.setTitle(title);

                String content = hit.getSourceAsMap().get("content").toString();//原始显示的content,而不是高亮显示的
                post.setContent(content);

                String status = hit.getSourceAsMap().get("status").toString();
                post.setStatus(Integer.valueOf(status));

                String createTime = hit.getSourceAsMap().get("createTime").toString();
                post.setCreateTime(new Date(Long.valueOf(createTime)));

                String commentCount = hit.getSourceAsMap().get("commentCount").toString();
                post.setCommentCount(Integer.valueOf(commentCount));

                // 处理高亮显示的结果
                HighlightField titleField = hit.getHighlightFields().get("title");//获取与title 有关的 高亮显示的内容
                if (titleField != null) {
                    post.setTitle(titleField.getFragments()[0].toString());//覆盖掉post原先没有高亮的title。从titleField中取到 高亮显示的值,getFragments返回的是数组。[0]表示只返回第一段。
                }

                HighlightField contentField = hit.getHighlightFields().get("content");//覆盖掉post原先没有高亮的content
                if (contentField != null) {
                    post.setContent(contentField.getFragments()[0].toString());
                }

                list.add(post);//将其放入集合
            }

            return new AggregatedPageImpl(list, pageable,
                    hits.getTotalHits(), response.getAggregations(), response.getScrollId(), hits.getMaxScore());// hits.getTotalHits()表示一共多少条数据
        }
    });

    System.out.println(page.getTotalElements());
    System.out.println(page.getTotalPages());
    System.out.println(page.getNumber());
    System.out.println(page.getSize());
    for (DiscussPost post : page) {
        System.out.println(post);
    }
}

Operation result:

Insert picture description here


111 data, 12 pages, current page 0, 10 data per page, followed by 10 data