ElasticSearch 分布式全文检索一、ElasticSearch 概述二、ElasticSearch 安装
1. Windows 下使用2. 安装 Kibana3. IK 分词器插件 三、Rest 风格 *** 作
1. 索引的命令 *** 作2. 文档的命令 *** 作 四、集成SpringBoot
1. 项目继承过程2. 索引的API *** 作2. 文档的API *** 作 五、京东搜索(实战)
一、ElasticSearch 概述
谁在使用:
ElasticSearch 和 Solr 对比:
ElasticSearch 简介:
Solr 简介:
对比:
- 当单纯的对已有的数据进行搜索时,Solr 更快。
当实时建立索引时,Solr 会产生io阻塞,查询性能较差,Elasticsearch 具有明显的优势。
随着数据的增加,Solr的搜索效率会变得更低。
总结:
ES 核心概念:
ElasticSearch 本身就是一个集群:
核心概念总结:
- 索引字段类型(mapping)文档(documents)
ElasticSearch 官网
ElasticSearch 官方下载地址
1. Windows 下使用- 解压下载的 windows 版本的 ElasticSearch :
熟悉目录!
bin # 启动文件 config # 配置文件 log4j2 日志配置文件 jvm.options java 虚拟机相关的配置 elasticsearch.yml elasticsearch 的配置文件!默认 9200 端口! lib # 相关jar 包 logs # 日志 modules # 功能模块 plugins # 插件
启动 ElasticSearch 服务,双击 该文件
测试访问 localhost:9200
安装 ElasticSearch 可视化界面 head 插件
下载地址
安装 head 插件需要 node.js 环境,所以先安装 node.js
Node.js 安装详解
安装node.js 后再 head 根目录下 执行:cnpm install 命令
运行 head :npm run start
测试访问 localhost:9100,发现无法连接上我们的 localhost:9200(ElasticSearch 服务),需解决跨域问题
修改 ElasticSearch 里的配置
重启 ElasticSearch 发现可以连接了
什么是Kibana?
Kibana 官网
Kibana 下载地址
注意:Kibana 版本需和 ElasticSearch 版本一致
下载后进行解压:
双击bin 目录下的 kibana.bat 文件 即可启动(同样需要node.js 的环境):
访问测试:http://localhost:5601
我们之后的所有 *** 作都从这里编写:
我们也可以设置成中文的(默认是英文的),编辑此文件
添加这行配置即可:
测试重启 kibana,发现切换成中文了!!!
什么是 IK 分词器?
IK 分词器下载地址
解压发送到我们的 ElasticSearch 的插件目录下即可:
重启 ES ,可以看到 IK 可以被加载了
使用 Kibana 进行测试:
发现 我们输入的词被自动拆分了,那么我们如何添加 自定义的 分词呢 ? 编辑添加的 ik 插件 下的文件
比如我们新建文件 myself.dic
重启 ES 测试效果:
Rest 风格说明:
- 创建一个索引:
PUT /索引(可以理解为数据库名)/类型名(未来没有这个了)/文档id {请求体}
在访问我们的head,发现多了个 test1,表示索引 test1 创建成功
点击数据浏览,查看test1,发现多了我们创建的这条数据了
那么 name 这个字段用不用指定类型呢,毕竟在我们关系型数据库是要指定类型的。
ElasticSearch 的数据类型有:
新建索引规则:
获取索引命令:GET [ 索引 ]
创建索引中的默认类型:PUT [索引名称]type名称(可以不写,默认_doc)[][文档名称]
同时可以看出,如果自己的文档字段没有指定类型,那么es会给我们默认配置字段类型!!
通过 GET /_cat/indices?v 可以看到所有索引的详细信息
如何修改数据呢?
- 通过 PUT 直接覆盖(弊端:如果里面有某个字段数据漏了,那个字段也会消失)
使用 POST …/update 来修改(只会修改传输的字段值,没有传输的字段不会改变)
删除索引;DELETE [ 索引 ]
添加一条数据:这里的索引若没有则新建
创建第二条数据:如果id 还会 1 就会对已有 id = 1 的那条数据进行更新
获取数据:GET /索引/TYPE/文档
根性数据,除了上述说的用PUT 的可以更新外,最好用 PST _update 进行更新:只会更新传输的字段,没有传输的字段保持原值。
搜索:
- 根据 id 搜索
GET test1/user/1
- 根据条件搜索:这里的name 后面没有加 " " 则会分词查询,加了 “ ” 则为精准查询
我们的查询结果中有一个分数栏,表示匹配度,匹配度越高,分数越高。
- 复杂查询:查询请求 + 参数体
6.查询结构解析:
查询出来的结果,只显示我们想要的字段信息:
排序查询
分页查询(数据下标还是从0开始的,和学的所有数据结构是一样的!)
布尔值查询:must(and),所有的条件都要符合 where id = 1 and name = xxx
布尔值查询:should(or),所有的条件都要符合 where id = 1 or name = xxx
布尔值查询:must_not
过滤器
- gt 大于 - gte 大于等于 - lt 小于 - lte 小于等于
一个字段,多个条件查询
精确查找
总结:term 只支持精确查询,match 模糊查询(分词),match + keyword 类型支持精确查询
精确查询多个值:
高亮查询
高亮查询 使用我们自定义标签
- 创建 maven 项目 elasticsearch-study 项目添加 pom 依赖:
4.0.0 org.springframework.boot spring-boot-starter-parent2.6.2 com.study elasticsearch-study0.0.1-SNAPSHOT elasticsearch-study Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter-data-elasticsearchorg.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-devtoolsruntime true org.springframework.boot spring-boot-configuration-processortrue org.projectlombok lomboktrue org.springframework.boot spring-boot-starter-testtest com.alibaba fastjson1.2.72 org.springframework.boot spring-boot-maven-pluginorg.projectlombok lombok
- 主启动类
package com.study.elasticsearchstudy; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ElasticsearchStudyApplication { public static void main(String[] args) { SpringApplication.run(ElasticsearchStudyApplication.class, args); } }
- 添加 RestHighLevelClient 配置类(配置连接信息)
package com.study.elasticsearchstudy.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ElasticSearchConfig { @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("127.0.0.1", 9200, "http") ) ); return client; } }
- 编写测试类:创建索引 kuang_index
package com.study.elasticsearchstudy; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.indices.CreateIndexRequest; import org.elasticsearch.client.indices.CreateIndexResponse; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.io.IOException; @SpringBootTest class ElasticsearchStudyApplicationTests { @Autowired private RestHighLevelClient restHighLevelClient; @Test void contextLoads() throws IOException { CreateIndexRequest request = new CreateIndexRequest("kuang_index"); CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); System.out.println(createIndexResponse); } }
6.测试结果:控制台打印输出 和 head 页面出现新建的索引
- 创建索引
@Configuration public class ElasticSearchConfig { @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost("127.0.0.1", 9200, "http") ) ); return client; } } @SpringBootTest class ElasticsearchStudyApplicationTests { @Autowired private RestHighLevelClient restHighLevelClient; @Test void contextLoads() throws IOException { CreateIndexRequest request = new CreateIndexRequest("kuang_index"); CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT); System.out.println(createIndexResponse); } }
- 获取索引
@Test public void testExisIndex() throws IOException { GetIndexRequest request = new GetIndexRequest("kuang_index"); boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT); System.out.println(exists); }
- 删除索引
@Test public void testDeleteIndex() throws IOException{ DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("test13"); AcknowledgedResponse delete = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); //delete.isAcknowledged() 为 true 为删除成功 System.out.println(delete.isAcknowledged()); }2. 文档的API *** 作
添加实体类:User
package com.study.elasticsearchstudy.pojo; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class User { private String name; private int age; }
- 添加文档
@Test public void testAdddocument() throws IOException { User user = new User("狂神",3); IndexRequest request = new IndexRequest("kuang_index"); request.id("1"); request.timeout(Timevalue.timevalueSeconds(1)); // 将我们的数据放入请求 json request.source(JSON.toJSONString(user), XContentType.JSON); // 客户端发送请求,获取相应结果 IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT); System.out.println(index.toString()); System.out.println(index.status()); }
- 判断文档是否存在
@Test public void testIsExists() throws IOException { GetRequest getRequest = new GetRequest("kuang_index", "1"); // 不获取返回的 _source 的上下文 getRequest.fetchSourceContext(new FetchSourceContext(false)); //不做排序 getRequest.storedFields("_none_"); boolean exists = restHighLevelClient.exists(getRequest, RequestOptions.DEFAULT); System.out.println(exists); }
- 获取文档信息
@Test public void testGetdocument() throws IOException { GetRequest getRequest = new GetRequest("kuang_index", "1"); GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); System.out.println(getResponse.getSourceAsString());//打印文档的内容 System.out.println(getRequest); }
- 更新文档
@Test public void testUpdatedocument(){ UpdateRequest updateRequest = new UpdateRequest("kuang_index", "1"); updateRequest.timeout("1s"); User user = new User("狂神说Java", 18); updateRequest.doc(JSON.toJSONString(user),XContentType.JSON); UpdateResponse update = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT); System.out.println(update.status()); }
- 删除文档
@Test void testDeleteRequest(){ DeleteRequest request = new DeleteRequest("kuang_index", "1"); request.timeout("1s"); DeleteResponse delete = restHighLevelClient.delete(request, RequestOptions.DEFAULT); System.out.println(delete.status()); }
- 批量导入数据
@Test void testBulkRequest() throws IOException { BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("10s"); ArrayListusers = new ArrayList<>(); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); users.add(new User("kaungsheng",3)); for (int i = 0 ; i < users.size();i++) { // 批量更新和批量删除,就在这里修改对应的请求就可以了 bulkRequest.add(new IndexRequest("kuang_index") .id(""+(i+1))//不设置id,会自动给一个随机的id,不会重复 .source(JSON.toJSONString(users.get(i)),XContentType.JSON)); } BulkResponse bulkItemResponses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); //是否失败 false=成功/true=失败 System.out.println(bulkItemResponses.hasFailures()); }
- 条件查询
@Test void testSearch() throws IOException { SearchRequest searchRequest = new SearchRequest("kuang_index"); // 构建搜索条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 查询条件,我们可以使用 QueryBuilders 工具来实现 // QueryBuilders.termQuery 精确 // QueryBuilders.matchAllQuery() 匹配所有 TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "kaungsheng"); // MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery(); searchSourceBuilder.query(termQueryBuilder); searchSourceBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); searchRequest.source(searchSourceBuilder); SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); System.out.println(JSON.toJSONString(search.getHits())); System.out.println("===================================="); for (SearchHit documentFields : search.getHits().getHits()) { System.out.println(documentFields.getSourceAsMap()); } }五、京东搜索(实战)
- 创建 maven 项目 elasticsearch.jdpom
org.jsoup jsoup1.10.2 org.springframework.boot spring-boot-starter-data-elasticsearchorg.springframework.boot spring-boot-starter-thymeleaforg.springframework.boot spring-boot-starter-weborg.springframework.boot spring-boot-devtoolsruntime true org.springframework.boot spring-boot-configuration-processortrue org.projectlombok lomboktrue org.springframework.boot spring-boot-starter-testtest com.alibaba fastjson1.2.76 compile
- properties
server.port=9090 #关闭 thymeleaf 缓存 spring.thymeleaf.cache=false
- 主启动类
package com.study.elasticsearchjd; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ElasticsearchJdApplication { public static void main(String[] args) { SpringApplication.run(ElasticsearchJdApplication.class, args); } }
- 配置类
package com.study.elasticsearchjd.config; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class ElasticSearchClientConfig { @Bean public RestHighLevelClient restHighLevelClient(){ RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("127.0.0.1", 9200, "http"))); return client; } }
- pojo
package com.study.elasticsearchjd.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class Content { private String title; private String img; private String price; }
- 工具类 (用来爬取网站页面数据)
package com.study.elasticsearchjd.utils; import com.study.elasticsearchjd.pojo.Content; import org.jsoup.Jsoup; import org.jsoup.nodes.document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; public class HtmlParseUtil { public static void main(String[] args) throws IOException { HtmlParseUtil.parseJD("java").forEach(System.out::println); } public static ListparseJD(String keyword) throws IOException { /// 使用前需要联网 // 请求url String url = "http://search.jd.com/search?keyword=" + keyword; // 1.解析网页(jsoup 解析返回的对象是浏览器document对象) document document = Jsoup.parse(new URL(url), 30000); // 使用document可以使用在js对document的所有 *** 作 // 2.获取元素(通过id) Element j_goodsList = document.getElementById("J_goodsList"); // 3.获取J_goodsList ul 每一个 li Elements lis = j_goodsList.getElementsByTag("li"); // System.out.println(lis); // 4.获取li下的 img、price、name // list存储所有li下的内容 List contents = new ArrayList (); for (Element li : lis) { // 由于网站图片使用懒加载,将src属性替换为data-lazy-img String img = li.getElementsByTag("img").eq(0).attr("data-lazy-img");// 获取li下 第一张图片 String name = li.getElementsByClass("p-name").eq(0).text(); String price = li.getElementsByClass("p-price").eq(0).text(); // 封装为对象 Content content = new Content(name,img,price); // 添加到list中 contents.add(content); } // System.out.println(contents); // 5.返回 list return contents; } }
- 业务类
package com.study.elasticsearchjd.service; import com.alibaba.fastjson.JSON; import com.study.elasticsearchjd.pojo.Content; import com.study.elasticsearchjd.utils.HtmlParseUtil; import org.apache.lucene.util.QueryBuilder; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.core.Timevalue; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; //业务编写 @Service public class ContentService { @Autowired private RestHighLevelClient restHighLevelClient; public Boolean parseContent(String keywords) throws IOException { Listcontents = HtmlParseUtil.parseJD(keywords); //把查询到的数据放入es中 BulkRequest bulkRequest = new BulkRequest(); bulkRequest.timeout("2m"); for (int i = 0; i < contents.size(); i++) { bulkRequest.add( new IndexRequest("jd_good").source(JSON.toJSONString(contents.get(i)), XContentType.JSON)); } BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT); return !bulk.hasFailures(); } public List
- controller
package com.study.elasticsearchjd.controller; import com.study.elasticsearchjd.pojo.Content; import com.study.elasticsearchjd.service.ContentService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.util.List; import java.util.Map; @RestController public class ContentController { @Autowired private ContentService contentService; @GetMapping("/parse/{keyword}") public Boolean parse(@PathVariable("keyword") String keyword) throws IOException { return contentService.parseContent(keyword); } @GetMapping("/search/{keyword}/{pageNo}/{pageSize}") public List> search(@PathVariable("keyword") String keyword, @PathVariable("pageNo") int pageNo, @PathVariable("pageSize") int pageSize ) throws IOException { return contentService.searchPage(keyword,pageNo,pageSize); } }
- 测试结果:
vue解析高亮字段:
效果如下:即实现了高亮
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)