在独自一人的上海,居家办公,只有不断学习和工作,严苛自己进步,才能在暗黑时光中找到生命的真谛。茫茫人生像一片无际的汪洋,独帆流行的岁月,我能做的就是热爱自己喜欢的职业,探求学习的乐趣,正如接下来所学的Elasticsearch,当你局限于select的时候,那你看到的世界只有红红绿绿。相反不断的努力,你才能看到天空的繁星,大海的鲛鱼,绿野的骏马,以及宇宙的洪荒。
爱你所爱,想你所想。
------题记
Typora学习链接学习
https://blog.csdn.net/m0_46502538/article/details/119420273?ops_request_misc=&request_id=&biz_id=102&utm_term=Typora%E7%9A%84%E4%BD%BF%E7%94%A8%E3%80%81&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-119420273.142^v9^pc_search_result_control_group,157^v4^control&spm=1018.2226.3001.4187
学习老师:狂神
压缩包git地址:https://gitee.com/yujie.louis/elastic-search
此文代码提交链接
https://gitee.com/The-century-old/elasticsearch/tree/master/luli-es-api
我们讲解什么?
sql(模糊查询):select * from use like%狂神说%进行查询,如果是大数据,就十分慢!索引!
elasticsearch:搜索.全文检索
以后你只要,需要用到搜索,就可以用ES!(大数据量的情况下使用)
1998年4月,Google公司在美国硅谷成立,他是一家搜索引擎起家的公司。
Lucene是用java写成,目标是各种 中小型应用软件加入全文检索功能,因为好用而且开源,所以受程序员喜欢。
Elasticsearch,简称ES,es是一个开源的高扩展的分布式全文搜索引擎,他可以近乎实时的存储,检索数据;本身扩展性很好,可以扩展到上百台服务器,处理pb级别(大数据)的数据。es也是用java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是填的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索更简单。
基于权重
谁在使用Elasticsearch?
维基百科,电商平台,BI系统
Elasticsearch是一个实时分布式走索和分析引擎,它让你从前所未有的速度处理大数据成为可能。
他用于全文搜索,结构化搜索,分析以及将这三者混合使用。
维基百科使用Elasticsearch提供全文搜索并高亮关键字,以及输入实时搜索(search-sdyou-type)和搜索纠错(did-you-mean)等搜索建议功能。
Solr是Apache下得一个顶级开源项目,采用java开发,他是基于Lucene的全文搜索服务,Solr提供了比Lucene更为丰富的查询语言,同事实现了可配置,可扩展,并对索引,搜索性能进行了优化
Solr可以独立运行,运行在jetty,Tomcat等这些Servlet容器中,Solr索引的实现很简单,用post方法向Solr服务器发送一个描述field及其内容的xml文档,Solr根据xml文档添加,删除,更新索引。Solr搜索只需要发送Http GET请求,然后对solr返回的xml。json等格式的查询结果进行解析,组织页面布局。
solr的优点包括以下几个方面:
①高级的全文搜索功能;
②专为高通量的网络流量进行的优化;
③基于开放接口(XML和HTTP)的标准;
④综合的HTML管理界面;
⑤可伸缩性-能够有效地复制到另外一个Solr搜索服务器;
⑥使用XML配置达到灵活性和适配性;
⑦可扩展的插件体系。
比较
当单纯的对已有的数据进行搜索的时候,solr更快。也就是说数据已经存放在数据库中。
当实时建立索引,solr会产生io阻塞,查询性能较差,Elasticsearch具有明显的优势。
随着数据量的增加,solr的搜索效率会变得更低,而Elasticsearch没有什么明显的变化。
Elasticsearch VS Solr
1.es基本是开箱即用,非常简单。solr安装略微复杂。
2.Solr利用Zookeeper进行分布式管理,而Elasticsearch自带分布式协调管理功能。
3.solr支持更多格式的数据,比如json,xml,csy,而Elasticsearch仅支持json格式。
4.solr官方提供的功能更多,而Elasticsearch本身更注重于核心功能,高级功能多有第三方插件提供,例如图形界面需要kibana友好支撑。
5.solr查询快,但更新索引时慢(插入删除慢),用于电商查询多的应用
6.solr比较成熟,有一个更大,更成熟的用户,开发和贡献者社区,而Elasticsearch相对开发维护较少,更新太快,学习使用成本较高。
我的下载路径:D:\Elasticsearch
声明:jdk1.8,最低要求
官网
下载地址:https://www.elastic.co/cn/downloads/?elektra=home&storm=hero
https://www.elastic.co/cn/downloads/elasticsearch
Windows下安装
解压即可使用
bin 启动文件
config 配置文件
log4j2 日志配置文件
jvm.options java虚拟机相关的配置
elasticsearch.yml Elasticsearch的配置文件 默认端口9200端口,存在跨域问题。
jdk 环境
lib 相关jar包
logs 日志
modules 功能模块
plgins 插件 ik分词器
bin目录elasticsearch.bat文件
name: node节点名称
cluster_name: 集群名称(默认的集群名称就是elasticsearch)
version.number: 5.6.0,es版本号
{
"name" : "陆离",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "jw6kBFqZRQWIKp96dzR0kg",
"version" : {
"number" : "7.6.1",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "aa751e09be0a5072e8570670309b1f12348f023b",
"build_date" : "2020-02-29T00:15:25.529771Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
自成集群,自己生成一个uuid
“tagline” : “You Know, for Search”
标语:你知道的为了搜索
安装可视话界面es head的创建
https://github.com/mobz/elasticsearch-head
前提:安装淘宝镜像
cmd 输入 npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm -v查看版本
D:\Elasticsearch\elasticsearch-head-master\elasticsearch-head-master> cnpm install
D:\Elasticsearch\elasticsearch-head-master\elasticsearch-head-master> npm run start
解决跨域问题
控制台会报错
跨域:跨端口,跨网站
访问9100会存在跨域问题
elasticsearch-7.6.1\config\elasticsearch.yml
#配置跨域 开启此功能 允许所有人
http.cors.enabled: true
http.cors.allow-origin: "*"
bin 启动文件
创建索引注意索引存在大写可能会建立不成功
就把索引当作一个数据库。
下载地址:https://www.elastic.co/cn/downloads/past-releases/kibana-7-6-1
下载完毕后,解压需要很久!是一个标准的工程
好处:开箱即用,拆箱即用。
默认端口:5601
http://localhost:5601/
kibana.bat
我们之后的所有操作都在设置写。
config/kibana.yml
将配置修改为i18n.locale: “zh-CN”
即可进行汉化
Relational DB(Mysql) | Elasticsearch |
---|---|
数据库(tables) | 索引(indices) |
表(table) | types慢慢会弃用 |
行(rows) | document(文档) |
字段(columns) | fields |
物理设计
Elasticsearch在后台把每个索引划分为多个分片,每分分片可以在集群中的不同服务器间迁移。默认集群就是elasticsearch
逻辑设计
elasticsearch中,每个索引就相当于一个库,这就是术语的使用,,在elasticsearch中,索引被分为多个分片,每个分片是一个Lucene的索引。所以一个elasticsearch索引是由多个Lucene索引组成的,因为elasticsearch的底层是Lucene,
例如:在博客中搜索Linux就不可能出现python。如果搜索python就不可能出现linux。
什么是IK分词器?
分词:即把一段中文或者别日得划分为一个个的关键字。我们在搜索的时候会把自己的信息进行分词,,会把数据库中或者索引库厚葬的数据进行分词,饭后进行一个匹配操作,默认的中文分词是将每一个字看成一个词,比如“什么是IK分词”会被分为“什”,“么”,“是”·····这显然是不符合要求的,所以我们需要安装中文分词器ik来解决这个问题。
如果使用中文,建议使用ik分词器!
ik提供了亮哥哥分词算法:ik_smart和ik_max_word,其中ik_smart字少切分,ik_max_word为最细粒度划分!
https://github.com/medcl/elasticsearch-analysis-ik/releases?page=5
https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.6.1
下载后解压到plugins
D:\Elasticsearch\ES7.6.1\elasticsearch-7.6.1-windows-x86_64\elasticsearch-7.6.1\plugins\ik
重启ES
D:\Elasticsearch\ES7.6.1\elasticsearch-7.6.1-windows-x86_64\elasticsearch-7.6.1\bin>elasticsearch-plugin.bat list
kibana.bat
查看分词效果
ik_smart为最少切分
ik_max_word最细力度切分
问题
可能有时候分词会将你想要的词语分开,所以就需要自己加到自己的字典中(IKAnalyzer.cfg.xml)
D:\Elasticsearch\ES7.6.1\elasticsearch-7.6.1-windows-x86_64\elasticsearch-7.6.1\plugins\ik\config\IKAnalyzer.cfg.xml
添加自己的字典文件
将自己的字典值文件引入到xml中
重启es
根据不同的功能设置不同的请求方式。
集成测试
PUT /索引名/~类型名(之后会弃用)~/文档id
{
请求题
}
PUT /test/type/1
{
"name":"自我测试",
"age":18
}
通过postMan
也可以访问到数据
指定类型
PUT /test2
{
"mappings": {
"properties": {
"name":{
"type": "text"
},
"age":{
"type": "long"
},
"birthday":{
"type": "date"
}
}
}
}
\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wDkJLsWZ-1651715841879)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220502194058527.png)\]
世界上太多优秀的人了,我们显得十分渺小,只有虚心学习,才能使自己有一点点的进步。
GET _cat/health
------展示信息---------
1651492099 11:48:19 elasticsearch yellow 1 1 6 6 0 0 3 0 - 66.7%
GET _cat/indices?v
------展示信息---------
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open test2 y_jYidoDTw-pdHp5z8T-Sg 1 1 0 0 283b 283b
yellow open test3 eoDnH0RPTm6RJjKNUQWjBw 1 1 1 0 9.9kb 9.9kb
yellow open test O5GCHSGJTTOPumacO6ungA 1 1 1 0 3.7kb 3.7kb
green open .kibana_task_manager_1 iGM1YKWlR_mv2Cmb1FQA-g 1 0 2 0 12.4kb 12.4kb
green open .apm-agent-configuration MGZzjUG4RYm1CVF9QMrjng 1 0 0 0 283b 283b
green open .kibana_1 0ldaoVAHS8e0ssmCK6l9hQ 1 0 15 38 142.1kb 142.1kb
POST /test3/_doc/1/_update
{
"doc":{
"age":23
}
}
------展示信息---------
_version(版本) 第几次操作数据
result 做了什么操作
#! Deprecation: [types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead.
{
"_index" : "test3",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
所有的删除命令使用delete
DELETE test
------展示信息---------
{
"acknowledged" : true
}
PUT /operate/_doc/1
{
"name":"lzp",
"age":22,
"sex":"男",
"birthday":"1999-11-28",
"desc":"一枚小小的程序员",
"tags":["技术控","胖子","工作狂"]
}
PUT /operate/_doc/3
{
"name":"张三",
"age":25,
"sex":"人妖",
"birthday":"1996-11-13",
"desc":"不男不女",
"tags":["泰国","丑女"]
}
这种模板只修改需要需改的数据,如果是put形式的请求,其他不修改的数据将会置空
POST /operate/_doc/4/_update
{
"doc":{
"name":"王五",
"age":29,
"tags":["山西","test"]
}
}
GET /operate/_doc/4
GET /operate/_doc/4
严重提示由于kibana内在机制,如果光标所在位置不在操作行将会报错
查询operate所有数据
GET /operate/_search
带条件查询
GET 索引名(表)/_search?q=字段名:查询数据
----------------------------------
GET operate/_search?q=name:法外狂徒
搜索一般根据权重进行匹配查询,_score峰值越高,查询顺序越靠前。
name:字段名
GET operate/_search
{
"query": {
"match": {
"name": "王五"
}
}
}
hits:查询出的是索引和文档信息
查询结果
查询总数total
relation匹配形式
通过_score判断谁是更为精准的查询结果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.5801352,
"hits" : [
{
"_index" : "operate",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.5801352,
"_source" : {
"name" : "王五五",
"age" : 30,
"sex" : "人妖",
"birthday" : "1994-11-13",
"desc" : "男",
"tags" : [
"俄罗斯",
"狗贼"
]
}
},
·········
]
}
}
“_source”: [“字段名1”,“字段名2”,·······,“字段名n”]
sort:排序 order:排序方式
分页: from 从第几条开始查,size返回多少条数据 类似于sql中的limit
GET operate/_search
{
"query": {
"match": {
"name": "王五"
}
},
"_source": ["name","age"]
,"sort": [
{
"age": {
"order": "asc"
}
}
]
, "from": 0
, "size": 2
}
select name,age from “operate/_search ” where name like “王五” and age=30;
GET operate/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "王五"
}
},
{
"match": {
"age": "30"
}
}
]
}
}
,"_source": ["name","age"]
}
select name,age from “operate/_search ” where name like “六” or age=29;
select name,age,sex from “operate/_search ” where name !=“王五” and sex!=“女”;
GET operate/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"name": "王五"
}
},
{
"match": {
"sex": "女"
}
}
]
}
}
,"_source": ["name","age","sex"]
}
select name,age,sex from “operate/_search ” where name like “王五” and age >= 30 and age <= 40;
也可以单独查
GET operate/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "王五"
}
}
]
, "filter": {
"range": {
"age": {
"gte": 30,
"lte": 40
}
}
}
}
}
,"_source": ["name","age","sex"]
}
select * from “operate/_search” where tags like “山西” or like “胖子”;
GET operate/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"tags": "山西 胖子"
}
}
]
}
}
}
关于分词:
term,直接进行精确查询
match,先使用分词解析!(先分析文档,然后再通过分析的文档进行查询)
PUT testdb
{
"mappings": {
"properties": {
"name":{
"type": "text"
},
"desc":{
"type": "keyword"
}
}
}
-------------展示 -------------
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "testdb"
}
PUT testdb/_doc/1
{
"name":"用户1",
"desc":"用户说明1"
}
-------------展示 -------------
{
"_index" : "testdb",
"_type" : "_doc",
"_id" : "1",
"_version" : 4,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1
}
GET testdb/_search
keyword未被拆分
GET _analyze
{
"analyzer": "keyword",
"text": ["用户说明2"]
}
-------------展示 -------------
{
"tokens" : [
{
"token" : "用户说明2",
"start_offset" : 0,
"end_offset" : 5,
"type" : "word",
"position" : 0
}
]
}
standard可以看到被拆分了
GET _analyze
{
"analyzer": "standard",
"text": ["用户说明2"]
}
-------------展示 -------------
{
"tokens" : [
{
"token" : "用",
"start_offset" : 0,
"end_offset" : 1,
"type" : "",
"position" : 0
},
{
"token" : "户",
"start_offset" : 1,
"end_offset" : 2,
"type" : "",
"position" : 1
},
{
"token" : "说",
"start_offset" : 2,
"end_offset" : 3,
"type" : "",
"position" : 2
},
{
"token" : "明",
"start_offset" : 3,
"end_offset" : 4,
"type" : "",
"position" : 3
},
{
"token" : "2",
"start_offset" : 4,
"end_offset" : 5,
"type" : "",
"position" : 4
}
]
}
细节总结,text和keyword的区别
如果type是text将会被分词解析,如果是keyword将不能被分词解析
因为type为text,所以可以被分词解析,即可得到模糊查询的数据
PUT testdb/_doc/3
{
"t1":"22",
"t2":"2022-04-21"
}
PUT testdb/_doc/4
{
"t1":"33",
"t2":"2023-11-21"
}
GET testdb/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"t1": "22"
}
},
{
"term": {
"t1": "33"
}
}
]
}
}
}
当指定highlight的属性值之后,所查询的json数据将会被高亮显示
GET operate/_search
{
"query": {
"match": {
"name": "五六"
}
}
, "highlight": {
"fields": {
"name": {}
}
}
}
pre_tags:相当于前置标签
post_tags:相当于闭合标签
GET operate/_search
{
"query": {
"match": {
"name": "五六"
}
}
, "highlight": {
"pre_tags": "",
"post_tags": "
",
"fields": {
"name": {}
}
}
}
这些查询mysql都能做,只是mysql效率比较低
引入的以来版本要和安装的es版本一致
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-elasticsearchartifactId>
<version>7.6.1version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.62version>
dependency>
配置config文件
/**
* 陆离
* 2022/5/3 2:45:13
*/
@Configuration
public class ElasticsearchClientConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1",9200,"http")
)
);
return client;
}
}
/**
* 测试索引的创建 Request
*/
@Test
void testCreateIndex() throws IOException {
//1.创建索引请求
CreateIndexRequest request = new CreateIndexRequest("luli");
//2.执行请求
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
/**
* 测试索引的获取 Request
*/
@Test
void testGetIndex() throws IOException {
//1.获取索引
GetIndexRequest request = new GetIndexRequest("luli2");
//2.判断索引是否存在
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 测试索引的删除 Request
*/
@Test
void testDeleteIndex() throws IOException {
//1.获取索引
DeleteIndexRequest request = new DeleteIndexRequest("luli2");
//2.判断索引是否存在
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
//3.是否存在
System.out.println(delete.isAcknowledged());
}
/**
* 测试索引的删除进阶版
*/
@Test
void testDeleteIndexs() throws IOException {
//1.获取索引
GetIndexRequest requests = new GetIndexRequest("luli");
//2.判断索引是否存在
boolean exists = client.indices().exists(requests, RequestOptions.DEFAULT);
if (exists) {
//1.获取索引
DeleteIndexRequest request = new DeleteIndexRequest("luli");
//2.判断索引是否存在
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
System.out.println("索引删除成功:" + delete.isAcknowledged());
} else {
System.out.println("索引不存在");
}
}
/**
* 测试添加文档
* 纯新的数据
* @throws IOException
*/
@Test
void testAddDocuments() throws IOException {
//创建对象
List<Users> users = usersService.getUsers("小李");
Users users1 = new Users(null, "ES数据测试数据", "13934084972", "山西省晋中市榆次区", "2022-05-03", "一枚程序猿");
//创建请求
IndexRequest request = new IndexRequest("luli2");
//规则
request.id("1");
//超时设置为1秒
request.timeout(TimeValue.timeValueSeconds(1));
//将数据放入请求 json 注意在pom文件中需要引入fastjson
String userData = JSON.toJSONString(users1);
request.source(userData, XContentType.JSON);
//客户端发送请求,获取响应的结果
IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
System.out.println(indexResponse.toString());
//获取状态 CREATED创建
System.out.println(indexResponse.status());
}
/**
* 获取文档,判断文档是否存在
* @throws IOException
*/
@Test
void testGetDocuments() throws IOException {
GetRequest getRequest = new GetRequest("luli2", "1");
//不获取返回的_sorce的上下文了
getRequest.fetchSourceContext(new FetchSourceContext(false));
//不获取返回的排序字段
getRequest.storedFields("_none_");
boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
System.out.println(exists);
}
/**
* 获取文档信息
* @throws IOException
*/
@Test
void teseGetDocument() throws IOException {
GetRequest getRequest = new GetRequest("luli2", "1");
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
//通过Map类型返回
Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
System.out.println("通过Map类型返回:"+sourceAsMap);
//通过String类型返回
String sourceAsString = getResponse.getSourceAsString();
System.out.println("通过String类型返回:"+sourceAsString);
//返回整体数据
System.out.println(getResponse);
}
/**
* 更新文档信息
*
* @throws IOException
*/
@Test
void teseUpdateDocument() throws IOException {
//更新luli2中1号的文档信息
UpdateRequest updateRequest = new UpdateRequest("luli2", "1");
updateRequest.timeout("1s");
//创建一个修改对象
Users users1 = new Users(null, "ES数据测试数据修改", "13934084972", "山西省晋中市榆次区庄子乡", "2022-06-03", "程序猿");
updateRequest.doc(JSON.toJSONString(users1), XContentType.JSON);
UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
System.out.println("状态:" + update.status());
}
/**
* 删除文档信息
*
* @throws IOException
*/
@Test
void teseDeleteDocument() throws IOException {
DeleteRequest request = new DeleteRequest("luli2", "3");
//超时请求,超过指定事件将不会再被请求
request.timeout("1s");
DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
//NOT_FOUND 不存在 OK成功
System.out.println("状态:" + delete.status());
}
/**
* 批量文档文档插入
* 也可以进行批量的删除和修改
*
* @throws IOException
*/
@Test
void teseBulkRequeRequest() throws IOException {
//创建批量请求
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("10s");
//数据库拿到数据
List<Users> users = usersService.getUsers(null);
//批量插入
for (int i = 0; i < users.size(); i++) {
bulkRequest.add(
new IndexRequest("luli3")
.id("" + (i+1))
.source(JSON.toJSONString(users.get(i)), XContentType.JSON)
);
}
BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
//是否执行失败 true是失败 false是成功
System.out.println("是否执行失败:" + bulkResponse.hasFailures());
}
注意点
查询的时候
QueryBuilders.termQuery(key,value);
可能会查询失败在key值后一定 要交(.keyword)才可以查询到。
/**
*
* @throws IOException termQuery 精确匹配
* SearchRequest 搜索请求
* SearchSourceBuilder 条件构造
* HighlightBuilder 构建高亮
* TermQueryBuilder 精确查询
* QueryBuilders.termQuery("字段名" + ".keyword" ,"value值");
*/
@Test
void testSearch() throws IOException {
//新建查询索引
SearchRequest searchRequest = new SearchRequest("luli3");
//构建搜索条件 构造器
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//QueryBuilders.matchAllQuery() 全量匹配
//查询条件 使用QueryBuilders快速匹配
//ueryBuilders.termQuery 精确匹配
//QueryBuilders.matchAllQuery() 匹配所有
//要设定keyword否则将无法查询出结果
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name" + KEY_WORD, "小李");
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//作为分页使用,空值为默认数值
// sourceBuilder.from();
// sourceBuilder.size();
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println(JSON.toJSONString(searchResponse.getHits()));
System.out.println("================================");
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
System.out.println(documentFields.getSourceAsMap());
}
}
数据问题?数据库获取,消息队列获取,都可以成为数据源头,爬虫!
爬取数据:(获取请求返回页面信息,筛选出我们想要的数据就可以了)
jsoup包
<dependency>
<groupId>org.jsoupgroupId>
<artifactId>jsoupartifactId>
<version>1.10.2version>
dependency>
package com.luli.Utils;
import com.luli.entity.Content;
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.unit.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.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import javax.naming.directory.SearchResult;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 陆离
* 2022/5/3 19:31:07
* 解析网页工具类
*/
public class HtmlParseUtils {
@Autowired
RestHighLevelClient restHighLevelClient;
public List<Content> parseID(String keywords) throws IOException {
//获取请求 https://search.jd.com/Search?keyword=
//前提需要链接网络 不能获取ajax数据
String url = "https://search.jd.com/Search?keyword=" + keywords;
//解析网页返回的就是js页面 document对象
Document document = Jsoup.parse(new URL(url), 3000);
//所有在js中使用的方法都能用了
Element element = document.getElementById("J_goodsList");
//获取所有li元素
Elements li = element.getElementsByTag("li");
List<Content> contentList = new ArrayList<>();
//获取元素中的内容 每一个li标签
for (Element el : li) {
//关于图片很多的网址,所有的图片都是延迟加载的
String img = el.getElementsByTag("img").eq(0).attr("data-lazy-img");
String price = el.getElementsByClass("p-price").eq(0).text();
String title = el.getElementsByClass("p-name").eq(0).text();
String words = el.getElementsByClass("promo-words").eq(0).text();
Content content = new Content();
content.setImg(img);
content.setPrice(price);
content.setTitle(title);
content.setWords(words);
contentList.add(content);
}
return contentList;
}
/**
* 获取数据,实现搜索功能
* @param keyword
* @param pageNo
* @param pageSize
* @return
*/
public List<Map<String, Object>> searchPage(String keyword, int pageNo, int pageSize) throws IOException {
if (pageNo <= 1) {
pageNo = 1;
}
//条件搜素
SearchRequest searchRequest = new SearchRequest("jd_goods");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//分页
sourceBuilder.from(pageNo);
sourceBuilder.size(pageSize);
//精准匹配关键字
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("title", keyword);
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//执行搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//解析结果
List<Map<String, Object>> list = new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
list.add(documentFields.getSourceAsMap());
}
return list;
}
}
E:\wwwwwwwwwwwwwwww\elasticsearch\luli-es-vue>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (luli-es-vue)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to E:\wwwwwwwwwwwwwwww\elasticsearch\luli-es-vue\package.json:
{
"name": "luli-es-vue",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
Is this OK? (yes) y
E:\wwwwwwwwwwwwwwww\elasticsearch\luli-es-vue>npm install vue
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
+ [email protected]
added 21 packages from 43 contributors and audited 21 packages in 39.092s
1 package is looking for funding
run `npm fund` for details
found 0 vulnerabilities
E:\wwwwwwwwwwwwwwww\elasticsearch\luli-es-vue>npm install axios
npm WARN [email protected] No description
npm WARN [email protected] No repository field.
+ [email protected]
added 8 packages from 11 contributors and audited 29 packages in 21.875s
2 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
在E:\wwwwwwwwwwwwwwww\elasticsearch\luli-es-vue\node_modules\axios\dist路径下把axios.min.js放入java的js目录下
在E:\wwwwwwwwwwwwwwww\elasticsearch\luli-es-vue\node_modules\vue\dist路径下把vue.min.js放入java的js目录下
在index中导入vue