ElasticSearch全文检索图书案例

本章内容概述

1、ElasticSearch数据准备
2、通过Java进行全文检索
3、效果展示

1、ElasticSearch添加数据

1.1 创建索引

PUT /libary
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 0
  },
  "mappings": {
    "book":{
      "properties":{
        "name":{
          "type":"text",
          "analyzer":"ik_max_word"
        },
        "price":{
          "type":"double"
        },
        "author":{
          "type":"text",
          "analyzer":"ik_max_word"
        },
        "house":{
          "type":"text",
          "analyzer":"ik_max_word"
        },
        "desc":{
          "type":"text",
          "analyzer":"ik_max_word"
        },
        "publish":{
          "type":"date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        }
      }
    }
  }
}

1.2 添加数据

	图书数据:图书编号、书籍名、书籍价格、作者、出版社、描述、出版日期
### 图书数据:图书编号、书籍名、书籍价格、作者、出版社、描述、出版日期

POST /libary/book
{
  "id":"101",
  "name":"Spring实战(第4版)",
  "price":78.30,
  "author":"Craig Walls 沃尔斯 著,张卫滨 译",
  "house":"人民邮电出版社",
  "desc":"《Spring实战(第4版)》是经典的、畅销的Spring学习和实践指南。第4版针对Spring 4进行了全面更新。全书分为四部
	分。第1部分介绍Spring框架的核心知识。第二部分在此基础上介绍了如何使用Spring构建Web应用程序。第三部分告别前端,介绍了
	如何在应用程序的后端使用Spring。",
  "publish":"2016-04-01"
}

POST /libary/book
{
  "id":"102",
  "name":"Spring Boot实战",
  "price":41.60,
  "author":"克雷格·沃斯(Craig Walls) 著,丁雪丰 译",
  "house":"人民邮电出版社",
  "desc":"本书以Spring应用程序开发为中心,全面讲解如何运用Spring Boot提高效率,使应用程序的开发和管理更加轻松有趣。作
	者行文亲切流畅,以大量示例讲解了Spring Boot在各类情境中的应用,内容涵盖起步依赖、Spring Boot CLI、Groovy、Grails、
	Actuator。对于Spring Boot开发应用中较为繁琐的内容,附录奉上整理完毕的表格,一目了然,方便读者查阅。",
  "publish":"2016-09-01"
}

POST /libary/book
{
  "id":"103",
  "name":"Spring Cloud与Docker微服务架构实战(第2版)",
  "price":72.70,
  "author":"周立 著",
  "house":"电子工业出版社",
  "desc":"本书基于Spring Cloud Edgware RELEASE 与Docker 17.09,以指导技术团队实现微服务架构落地为宗旨,覆盖微服务理
	论、微服务开发框架(Spring Cloud)及运行平台(Docker)三大主题。",
  "publish":"2018-07-01"
}

POST /libary/book
{
  "id":"104",
  "name":"Java EE互联网轻量级框架整合开发",
  "price":83.90,
  "author":"杨开振,周吉文,梁华辉,谭茂华 著",
  "house":"电子工业出版社",
  "desc":"随着移动互联网的兴起,以Java技术为后台的互联网技术占据了市场的主导地位,而在Java互联网后台开发中,SSM框架(
	Spring+Spring MVC+MyBatis)成为了主要架构,本书以此为焦点从入门到实际工作要求讲述了SSM框架的技术应用;",
  "publish":"2017-07-01"
}

POST /libary/book
{
  "id":"105",
  "name":"Java EE框架整合开发入门到实战",
  "price":64.20,
  "author":"陈恒,楼偶俊,张立杰 著",
  "house":"清华大学出版社",
  "desc":"本书详细讲解了Java EE中Spring、Spring MVC和MyBatis三大框架(SSM)的基础知识和实际应用。为了更好地帮助读者
	学习SSM框架,本书以大量案例介绍了SSM框架的基本思想、方法和技术。",
  "publish":"2018-08-01"
}

POST /libary/book
{
  "id":"106",
  "name":"现货正版 深入理解Java虚拟机:JVM高级",
  "price":50.90,
  "author":"周志明 著",
  "house":"机械工业出版社",
  "desc":"《深入理解Java虚拟JVM高级特性与佳实践》由周志明所著,超级畅销书全新升级,第1版两年内印刷近10次,Java图书领域
	公认的经典著作,繁体版台湾发行。 基于新JDK1.7,围绕内存管理、执行子系统、程序编译与优化、高效并发等核心主题对JVM进行
	全面而深入的分析,深刻揭示JVM的工作原理。 以实践为导向,通过大量与实际生产环境相结合的案例展示了解决各种常见JVM问题的
	技巧和佳实践。",
  "publish":"2013-06-01"
}

POST /libary/book
{
  "id":"107",
  "name":"Java学习黄金组合套装 ",
  "price":142.30,
  "author":"明日科技 著",
  "house":"吉林大学出版社",
  "desc":"《Java项目开发实战入门》以一起来画画、通讯录系统、明日彩票预测系统、小小五子棋、企业进销存管理系统、企业QQ(
	局域网版)、九宫格记忆网和铭成在线考试系统8个精选项目为案例,从趣味性和实际应用角度出发,采用了当前主流技术,读者可以
	从这些项目中体验到编程的乐趣并获得实战经验。",
  "publish":"2017-09-01"
}

POST /libary/book
{
  "id":"108",
  "name":"Java 8入门与实践实验指导及习题解析",
  "price":37.80,
  "author":"丁振凡 著",
  "house":"水利水电出版社",
  "desc":"《Java 8入门与实践实验指导及习题解析(微课视频版)》在内容体系上与笔者编写的《Java 8入门与实践(微课视频版)
	》紧密配合。两本书的各章次序保持一致,目的是为每章的实践环节提供一个详细指导。每章包括知识要点、实验指导、习题解析。知
	识要点部分对《Java 8入门与实践(微课视频版)》每章的知识点进行了提炼。实验指导部分包括实验目的、样例调试和编程练习。其
	中样例调试包括基本训练题和综合样例题,基本训练题的目标是强化概念理解,分步启发引导学生在编程调试过程中进行自我知识总
	结;综合样例题则是培养学生综合应用知识的能力。实验指导部分的编程题可供学生思考与练习。习题解析部分对《Java 8入门与实
	践(微课视频版)》一书每章的习题进行了详细的解答和分析。",
  "publish":"2019-05-01"
}


POST /libary/book
{
  "id":"109",
  "name":"web前端基础开发秘籍:HTML5 CSS3",
  "price":106.40,
  "author":"未来科技 著",
  "house":"中国水利水电出版社",
  "desc":"《HTML5+CSS3+JavaScript从入门到精通(标准版)》以基础知识、示例、实战案例相结合的方式详尽讲述了HTML、CSS、
	JavaScript及目前新的前端技术,html5移动开发html5实战html5canvashtml5apphtml5入门html5动画html5揭秘html游戏html5
	指南的基本知识都有涉及。全书分两大部分,共12章。",
  "publish":"2017-07-01"
}

POST /libary/book
{
  "id":"110",
  "name":"PHP从零基础到项目实战",
  "price":67.90,
  "author":"未来科技 著",
  "house":"中国水利水电出版社",
  "desc":"《PHP从零基础到项目实战(微课视频版)》从初学者角度出发,以基础知识、示例、实战案例相结合的方式,详细介绍了使
	用PHP进行网络开发、游戏开发、移动端后台开发、OA系统开发、服务器端开发等应该掌握的各方面技术。本书共24章,主要内容包括
	PHP概述、安装和配置PHP运行环境、PHP语言基础、操作字符串、使用正则表达式、操作数组、使用PHP与网页交互、PHP日期和时间
	处理、PHP会话处理、PHP图形图像处理、PHP文件系统处理、PHP面向对象程序设计、安装和使用MySQL、使用phpMyAdmin管理MySQL
	、使用PHP操作MySQL、使用PDO操作数据库、PHP加密技术、PHP与JavaScript技术、PHP与XML技术、PHP与Ajax技术、PHP与
	Socket技术、PHP错误和异常处理,最后两章通过购物网站和移动私密社区两个综合案例诠释PHP在实际项目中的具体应用。书中所有
	知识都结合具体实例进行介绍,将基础知识和实例相结合,可以使读者轻松领会PHP程序开发的精髓,快速提高开发技能。",
  "publish":"2019-01-01"
}

POST /libary/book
{
  "id":"111",
  "name":"海底两万里世界名著全10册",
  "price":39.80,
  "author":"让-亨利·卡西米尔·法布尔 著,徐海丽 编",
  "house":"中译出版社",
  "desc":"大自然中,有太多我们所不知道的事了,而它们又是客观存在的,只要你有心,就会发现另一个不一样的世界。那个世界里不
	乏有趣的见闻,并且充满了惊喜,它神秘而又充满了幻想,它就是昆虫的世界。在《昆虫记》里,详细介绍了昆虫世界里的生、老、病
	、死和喜、怒、哀、乐,时时让我们惊叹造物者的神奇。",
  "publish":"2016-06-01"
}

POST /libary/book
{
  "id":"112",
  "name":"环球国家地理百科全书",
  "price":137.30,
  "author":"王越 编",
  "house":"北京联合出版公司",
  "desc":"全书以行政区划和地理位置为纲,将各大洲以地理分布划分为若干国家单元,各单元中均以国家或地区为单位,为读者详细地
	介绍了世界各地精彩纷呈的方方面面。此外,我们为了将世界地理之美表达的更为全面和真实,特地在每卷书的最后加了一部分地理美
	文,让你在百科知识看到乏味之时,享受一下异样的地理之美。",
  "publish":"2016-06-01"
}

POST /libary/book
{
  "id":"113",
  "name":"福尔摩斯探案集全集10册",
  "price":128.80,
  "author":null,
  "house":"山东友谊出版社",
  "desc":null,
  "publish":"2010-06-01"
}

POST /libary/book
{
  "id":"114",
  "name":"新华字典(第11版)",
  "price":16.90,
  "author":"商务印书馆 编",
  "house":"商务印书馆",
  "desc":"《新华字典》是新中国第一部现代汉语字典,首次出版于1953年,原由新华辞书社编写,著名语言文字学家魏建功先生主持
	编写工作。1956年,新华辞书社并人当时的中国科学院语言研究所(1977年改属中国社会科学院)词典编辑室。《新华字典》历经多
	次修订出版,深受广大读者欢迎。在第11版出版之际,谨向为《新华字典》的编写、修订工作做出重要贡献的前辈学者们致以崇高的敬
	意。",
  "publish":"2011-06-01"
}

POST /libary/book
{
  "id":"115",
  "name":"古代汉语词典",
  "price":55.20,
  "author":"商务印书馆辞书研究中心 编",
  "house":"商务印书馆",
  "desc":"《古代汉语词典》自1998年出版以来,深受读者欢迎。至今已经过去了15年,有必要进行一次系统的修订,把质量提高到一
	个新的水平。",
  "publish":"2014-05-01"
}

POST /libary/book
{
  "id":"116",
  "name":"一看就停不下来的中国史",
  "price":52.60,
  "author":"最爱君 著",
  "house":"台海出版社",
  "desc":"硬气文人、戏精政客、失意将军、求生商人、谜案新解。在《一看就停不下来的中国史》中,我们会见到那些留名千古的人物
	,但读到的不再是猎奇,不再是抽离了人性的空洞规律,而是深伏于文字之下的,那呼之欲出的内在驱动力量。",
  "publish":"2018-10-01"
}

POST /libary/book
{
  "id":"117",
  "name":"Silent Spring寂静的春天 英文原版",
  "price":144.30,
  "author":"Rachel Carson(蕾切尔·卡森)著",
  "house":"Houghton Mifflin Harcourt",
  "desc":"《寂静的春天》1962年在美国问世时,是一本很有争议的书。它那惊世骇俗的关于农药危害人类环境的预言,不仅受到与之
	利害攸关的生产与经济部门的猛烈抨击,而且也强烈震撼了社会广大民众。你若有心去翻阅本世纪60年代以前的报纸或书刊,你将会发
	现几乎找不到“环境保护”这个词。",
  "publish":"2003-10-23"
}

POST /libary/book
{
  "id":"118",
  "name":"Baby Loves Spring 宝宝爱春天 纸板翻翻书",
  "price":23.50,
  "author":"Carson卡森 著",
  "house":"Little Simon",
  "desc":"儿童读物 Baby Loves Spring ",
  "publish":"2009-10-23"
}

2、通过Java进行全文检索

2.1 Dao层实现

Dao接口定义:
package com.jeebuilder.modules.generator.dao;

import com.jeebuilder.modules.generator.entity.BookEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;

/**
 * 
 * 
 * @author jerrychen
 * @email [email protected]
 * @date 2019-05-21 15:06:35
 */
@Mapper
public interface BookDao extends BaseMapper {
	
	public List> queryAllBook(Integer page,Integer limit);
	
	public List>  queryByString( String str,Integer page,Integer limit);

	public Integer queryBookCounts();
}

Dao实现类:
package com.jeebuilder.modules.generator.dao.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Repository;

import com.jeebuilder.common.utils.ClientUtils;

@Repository
public class BookDaoImpl {
	private TransportClient client = ClientUtils.getClient();
	
	/**
	 * 1 0 -10
	 * 2 10 - 10
	 * @param page
	 * @param limit
	 * @return
	 */
	public List> queryAllBook(Integer page,Integer limit){
		//查询所有图书信息
		List> bookList = new ArrayList<>();
		
		//指定一个index和type    
        SearchRequestBuilder search = client.prepareSearch("libary").setTypes("book");
        //使用原生排序优化性能
        search.addSort("_doc", SortOrder.ASC);
        
        //默认是查询所有
        search.setQuery(QueryBuilders.queryStringQuery("*:*")).setFrom((page-1)*limit).setSize(limit);

        //获得首次的查询结果
        SearchResponse scrollResp=search.get();
       
        //读取结果集数据
        for (SearchHit hit : scrollResp.getHits().getHits()) {
        	bookList.add(hit.getSourceAsMap());
        }

        return bookList;
	}
	
	
	public  List>  queryByString( String str,Integer page,Integer limit){
		//查询所有图书信息
		List> bookList = new ArrayList<>();
		
		//查询爱好或地址或姓名中包含"唱歌"的用户
		
		
		//指定一个index和type    
        SearchRequestBuilder search = client.prepareSearch("libary").setTypes("book");
        //使用原生排序优化性能
        search.addSort("_doc", SortOrder.ASC);
        
        //默认是查询所有
        search.setQuery(QueryBuilders.multiMatchQuery(str, "desc","house","name")).setFrom((page-1)*limit).setSize(limit);
        
        //设置高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);
        highlightBuilder.preTags("");
        highlightBuilder.postTags("");
        search.highlighter(highlightBuilder);

        //获得首次的查询结果
        SearchResponse scrollResp=search.get();
       
       

        //读取结果集数据
        for (SearchHit hit : scrollResp.getHits().getHits()) {
        	Map sourceAsMap = hit.getSourceAsMap();
        	//处理高亮片段
            Map highlightFields = hit.getHighlightFields();
            HighlightField nameField = highlightFields.get("name");
            HighlightField descField = highlightFields.get("desc");
            if(nameField!=null){
                org.elasticsearch.common.text.Text[] fragments = nameField.fragments();
                String nameTmp ="";
                for(org.elasticsearch.common.text.Text text:fragments){
                    nameTmp+=text;
                }
                //将高亮片段组装到结果中去
                sourceAsMap.put("name",nameTmp);
            }
            if(descField!=null){
                org.elasticsearch.common.text.Text[] fragments = descField.fragments();
                String nameTmp ="";
                for(org.elasticsearch.common.text.Text text:fragments){
                    nameTmp+=text;
                }
                //将高亮片段组装到结果中去
                sourceAsMap.put("desc",nameTmp);
            } 
        	
        	bookList.add(sourceAsMap);
        }
        
		
        return bookList;
	}
	
	public Integer queryBookCounts(String str) {
		//查询所有图书信息
		List> bookList = new ArrayList<>();
		
		//指定一个index和type    
        SearchRequestBuilder search = client.prepareSearch("libary").setTypes("book");
        //使用原生排序优化性能
        search.addSort("_doc", SortOrder.ASC);
        
        //默认是查询所有
        if (str == null || str.equals("")) {
        	search.setQuery(QueryBuilders.queryStringQuery("*:*"));
        }else {
        	search.setQuery(QueryBuilders.multiMatchQuery(str, "desc","house","name"));
        }
        //设置 search context 维护1分钟的有效期
        search.setScroll(TimeValue.timeValueMinutes(1));

        //获得首次的查询结果
        SearchResponse scrollResp=search.get();
       
       
        do {
            //读取结果集数据
            for (SearchHit hit : scrollResp.getHits().getHits()) {
            	bookList.add(hit.getSourceAsMap());
            }
           
            //将scorllId循环传递
            scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(TimeValue.timeValueMinutes(1)).execute().actionGet();
            
            //当searchHits的数组为空的时候结束循环,至此数据全部读取完毕
 		} while(scrollResp.getHits().getHits().length != 0);
		
        return bookList.size();
	}
}

2.2 Service层实现

Service接口:
package com.jeebuilder.modules.generator.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.jeebuilder.common.utils.PageUtils;
import com.jeebuilder.modules.generator.entity.BookEntity;

import java.util.List;
import java.util.Map;

/**
 * 
 *
 * @author jerrychen
 * @email [email protected]
 * @date 2019-05-21 15:06:35
 */
public interface BookService  extends IService  {

	//PageUtils queryPage(Map params); 
	
	public List> queryAllBook(Map params);

	public Integer queryBookCounts(Map params);
}


Service实现类
package com.jeebuilder.modules.generator.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeebuilder.common.utils.PageUtils;
import com.jeebuilder.common.utils.Query;

import com.jeebuilder.modules.generator.dao.BookDao;
import com.jeebuilder.modules.generator.dao.impl.BookDaoImpl;
import com.jeebuilder.modules.generator.entity.BookEntity;
import com.jeebuilder.modules.generator.service.BookService;

@Service("bookService")
public class BookServiceImpl  extends ServiceImpl  implements BookService {

	@Autowired
	private BookDaoImpl bookDaoImpl;

	/*
	 * @Override public PageUtils queryPage(Map params) {
	 * QueryWrapper queryWrapper = new QueryWrapper<>(); String key =
	 * params.get("key").toString(); // 如果查询条件的值不为空,就添加 like 关键字 if
	 * (StringUtils.isNotEmpty(key)){
	 * queryWrapper.like(params.get("column").toString(),params.get("key")); }
	 * IPage page = this.page( new Query().getPage(params),
	 * queryWrapper );
	 * 
	 * return new PageUtils(page); }
	 */

	public List> queryAllBook(Map params) {
		String str = (String) params.get("key");
		
		Integer page = Integer.parseInt((String)params.get("page")) ;
		
		Integer limit = Integer.parseInt((String)params.get("limit"));
		
		
		if (str == null || str.equals("")) {
			return bookDaoImpl.queryAllBook(page,limit);
		} else {
			return bookDaoImpl.queryByString(str,page,limit);
		}

	}

	@Override
	public Integer queryBookCounts(Map params) {
		// TODO Auto-generated method stub
		String str = (String) params.get("key");
		return bookDaoImpl.queryBookCounts(str);
	}

}

2.3 Controller层实现

package com.jeebuilder.modules.generator.controller;

import java.util.HashMap;
import java.util.Map;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.jeebuilder.common.utils.PageUtils;
import com.jeebuilder.common.utils.R;
import com.jeebuilder.modules.generator.service.BookService;

import io.swagger.models.auth.In;

/**
 * 
 *
 * @author jerrychen
 * @email [email protected]
 * @date 2019-05-21 15:06:35
 */
@RestController
@RequestMapping("generator/book")
public class BookController {
	@Autowired
	private BookService bookService;

	/**
	 * 列表
	 */
	@RequestMapping("/list")
	@RequiresPermissions("generator:book:list")
	public R list(@RequestParam Map params) {

//        PageUtils page = bookService.queryPage(params);

		Map map = new HashMap<>();
		// 放置查询的数据
		map.put("list", bookService.queryAllBook(params));

		Integer totalCount = bookService.queryBookCounts(params);

		Integer pageSize = Integer.parseInt((String) params.get("limit"));

		Integer totalPage = totalCount / pageSize;

		if (totalCount % 10 != 0) {
			totalPage++;
		}
		// 放置总数量

		map.put("totalCount", totalCount);

		// 放置页码
		map.put("pageSize", pageSize);
		// 放置总页数
		map.put("totalPage", totalPage);
		// 放置当前页
		//map.put("currPage", Integer.parseInt((String) params.get("currPage")));

		return R.ok().put("page", map);
	}


}

2.4 工具类实现

package com.jeebuilder.common.utils;

import java.net.InetAddress;
import java.net.UnknownHostException;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

public class ClientUtils {
	
	/**
	 *  创建访问es服务器的客户端对象
	 * @return TransportClient
	 */
	public static TransportClient getClient() {
		//指定ES集群
		Settings settings = Settings.builder().put("cluster.name", "myes").build();
		
		//创建访问es服务器的客户端
		TransportClient client = null;
		try {
			client = new PreBuiltTransportClient(settings).
									addTransportAddress(new TransportAddress(
											InetAddress.getByName("192.168.34.64"),9300));
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return client;
	}
		
}

3、效果展示

ElasticSearch全文检索图书案例_第1张图片

ort.client.PreBuiltTransportClient;

public class ClientUtils {

/**
 *  创建访问es服务器的客户端对象
 * @return TransportClient
 */
public static TransportClient getClient() {
	//指定ES集群
	Settings settings = Settings.builder().put("cluster.name", "myes").build();
	
	//创建访问es服务器的客户端
	TransportClient client = null;
	try {
		client = new PreBuiltTransportClient(settings).
								addTransportAddress(new TransportAddress(
										InetAddress.getByName("192.168.34.64"),9300));
	} catch (UnknownHostException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	return client;
}

}


# 3、效果展示
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210425151200601.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppbnRpYW56aGVuZw==,size_16,color_FFFFFF,t_70#pic_center)

你可能感兴趣的:(大数据,elasticsearch,java,全文检索)