springboot 2.2.x +ES 7.4.x 实现分词和高亮搜索

2022-05-12 11:25:51 浏览数 (1)

使用springboot2.2.1,elasticsearch7.4.2

1. pom
代码语言:javascript复制
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

其他依赖,web,lombok

代码语言:javascript复制
<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
2.application.properties

application.properties es默认没有密码,暂时未设定用户密码

代码语言:javascript复制
#elasticsearh
spring.elasticsearch.rest.uris=http://192.168.4.100:9200
3.实体类
代码语言:javascript复制
@Data
@NoArgsConstructor
//需要使用Document注解,indexName:库的名称,type:存储类型,一般使用bean的名称,
//分片(Shard)以及副本(Replica),分布式存储系统为了解决单机容量以及容灾的问题,都需要有分片以及副本机制。
@Document(indexName = "ems", type = "_doc", shards = 1, replicas = 0)
public class DocBean {

    @Id
    private Long id;

    @Field(type = FieldType.Keyword)
    private String firstCode;

    @Field(type = FieldType.Keyword)
    private String secordCode;

    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String content;

    @Field(type = FieldType.Integer)
    private Integer type;

    public DocBean(Long id, String firstCode, String secordCode, String content, Integer type) {
        this.id = id;
        this.firstCode = firstCode;
        this.secordCode = secordCode;
        this.content = content;
        this.type = type;
    }
}
4.dao
代码语言:javascript复制
public interface ElasticRepository extends ElasticsearchRepository<DocBean, Long> {

    //默认的注释
    //@Query("{"bool" : {"must" : {"field" : {"content" : "?"}}}}")
    Page<DocBean> findByContent(String content, Pageable pageable);

    Page<DocBean> findByFirstCode(String firstCode, Pageable pageable);

    Page<DocBean> findBySecondCode(String SecondCode, Pageable pageable);

}
5.service
代码语言:javascript复制
public interface ElasticService {

    void createIndex();

    void deleteIndex(String index);

    void save(DocBean docBean);

    void saveAll(List<DocBean> list);

    Iterator<DocBean> findAll();

    Page<DocBean> findByContent(String content);

    Page<DocBean> findByFirstCode(String firstCode);

    Page<DocBean> findBySecondCode(String SecondCode);

    Page<DocBean> query(String key);
}
代码语言:javascript复制
@Service("elasticService")
public class ElasticServiceImpl implements ElasticService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchTemplate;
    @Autowired
    private ElasticRepository elasticRepository;

    private Pageable pageable = PageRequest.of(0, 10);

    @Override
    public void createIndex() {
        elasticsearchTemplate.createIndex(DocBean.class);
        //创建mapping,使分词生效
        elasticsearchTemplate.putMapping(DocBean.class);
    }

    @Override
    public void deleteIndex(String index) {
        elasticsearchTemplate.deleteIndex(index);
    }

    @Override
    public void save(DocBean docBean) {
        elasticRepository.save(docBean);
    }

    @Override
    public void saveAll(List<DocBean> list) {
        elasticRepository.saveAll(list);
    }

    @Override
    public Iterator<DocBean> findAll() {
        return elasticRepository.findAll().iterator();
    }

    @Override
    public Page<DocBean> findByContent(String content) {
        return elasticRepository.findByContent(content, pageable);
    }

    @Override
    public Page<DocBean> findByFirstCode(String firstCode) {
        return elasticRepository.findByFirstCode(firstCode, pageable);
    }

    @Override
    public Page<DocBean> findBySecondCode(String SecondCode) {
        return elasticRepository.findBySecondCode(SecondCode, pageable);
    }

    @Override
    public Page<DocBean> query(String key) {
        return elasticRepository.findByContent(key, pageable);
    }
}
6.ctrl
代码语言:javascript复制
@RestController
@RequestMapping("/elastic")
public class ElasticController {

    @Autowired
    private ElasticService elasticService;

    @GetMapping("/init")
    public void init() {
        elasticService.createIndex();
        List<DocBean> list = new ArrayList<>();
        list.add(new DocBean(1L, "XX0193", "XX8064", "中国", 1));
        list.add(new DocBean(2L, "XX0210", "XX7475", "我是一个中国人", 1));
        list.add(new DocBean(3L, "XX0257", "XX8097", "我爱中华人民共和国", 1));
        elasticService.saveAll(list);

    }

    @GetMapping("/all")
    public Iterator<DocBean> all() {
        return elasticService.findAll();
    }

    @GetMapping("/findByContent")
    public Page<DocBean> findByContent(String content) {
        Page<DocBean> x = elasticService.findByContent(content);
        return x;
    }


    @GetMapping("/findByFirstCode")
    public Page<DocBean> findByFirstCode() {
        return elasticService.findByFirstCode("XX0193");
    }

    @GetMapping("/findBySecondCode")
    public Page<DocBean> findBySecondCode() {
        return elasticService.findBySecondCode("XX7475");
    }
}
7.测试

init方法初始化数据:http://localhost:8080/elastic/init 测试

8.高亮显示

上面已经实现了分词,因为ElasticsearchRepository提供的实现接口是封装好的,那我们就把接口的实现单独抽出来。 在实现类重写了ElasticsearchRepository提供的findByContent方法,添加前缀后缀

代码语言:javascript复制
@Override
    public Page<DocBean> findByContent(String content) {

        // 定义高亮字段
        HighlightBuilder.Field contentField = new HighlightBuilder.Field("content").preTags("<span>").postTags("</span>");
        // 构建查询内容
        QueryStringQueryBuilder queryBuilder = new QueryStringQueryBuilder(content);
        // 查询匹配的字段
        queryBuilder.field("content");

        SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(queryBuilder)
                .withHighlightFields(contentField).build();
        long count = elasticsearchTemplate.count(searchQuery, DocBean.class);
        System.out.println("系统查询个数:--》"   count);
        if (count == 0) {
            return null;
        }

        AggregatedPage<DocBean> queryForPage = elasticsearchTemplate.queryForPage(searchQuery, DocBean.class,
                new SearchResultMapper() {

                    @Override
                    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz,
                                                            Pageable pageable) {

                        List<DocBean> list = new ArrayList<DocBean>();
                        for (SearchHit searchHit : response.getHits()) {
                            if (response.getHits().getHits().length <= 0) {
                                return null;
                            }
                            DocBean DocBean = JSONObject.parseObject(searchHit.getSourceAsString(), DocBean.class);
                            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
                            //匹配到的content字段里面的信息
                            HighlightField contentHighlight = highlightFields.get("content");
                            if (contentHighlight != null) {
                                Text[] fragments = contentHighlight.fragments();
                                String fragmentString = fragments[0].string();
                                DocBean.setContent(fragmentString);
                            }
                            list.add(DocBean);

                        }
                        if (list.size() > 0) {
                            return new AggregatedPageImpl<T>((List<T>) list);
                        }
                        return null;
                    }

                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                        return null;
                    }
                });
        return queryForPage;
    }
Gitee

gitee地址

0 人点赞