ElasticSearch7.6

2023-11-27 14:51:21 浏览数 (1)

ElasticSearch

ElasticSearch概述

ElasticSearch,简称es,es是一个开源的高拓展分布式全文检索引擎,它可以近乎实时的存储检索数据;本身拓展性很好,它可以拓展到上百台服务器,处理PB级别的数据。es也使用java开发并使用Lucene的复杂性,从而让全文检索变得简单 据国际权威的数据库产品评测机构DB Engines的统计,2016年1月,ElasticSearch已超过solr等成为排名第一的搜索引擎类应用

ElasticSearch和solr的差别

ElasticSearch简介

ElasticSearch是一个实时分布式搜索和分析引擎,它让你以前所未有的速度处理大数据的可能 它用于全文搜索,结构化搜索,分析以及这三者混合使用 ElasticSearch是一个基于Apache Lucene™的开源搜索引擎。无论是在开源还是专有邻域,Lucene可以被认为是迄今为止最先进、性能最好的,功能最全的搜索引擎库。 但是。Lucene只是一个库。想要使用它,你必须使用java作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要更深入的了解检索的相关知识来理解它是如何工作的。 ElasticSearch也使用java开发并使用Lucene作为其核心来实现所有索引和功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文检索变得简单

Solr简介

Solr是Apache下的顶级开源项目,采用java开发,它是基于Lucene的全文检索服务器。solr提供优化比Lucene跟为丰富的查询语言,同时实现了可配置、可拓展,并对索引、搜索性能进行了优化 solr可以独立运行,运行在jetty、tomcat等这些servlet容器中,Sole索引的实现方法很简单,用post方法向solr服务器发送一条可描述Filed及其内容的XML文档,Solr根据xml文档的添加、删除、更新索引、Solr搜索只需要发送HTTP GET请求,然后对solr返回xml、json等格式的查询结果进行解析,组织页面布局、solr不提供构建UI的功能,solr提供了一个管理界面,通过管理界面可以对查询的solr的配置和运行情况 Solr是一个开源搜索平台,用于构建搜索应用程序。 是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口 它建立在Lucene(全文搜索引擎)之上。 Solr是企业级的,快速的和高度可扩展的。

Lucene简介

Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能的一个开源框架。Lucene 目前是 Apache Jakarta 家族中的一个开源项目。也是目前最为流行的基于 Java 开源全文检索工具包。

目前已经有很多应用程序的搜索功能是基于 Lucene 的,比如 Eclipse 的帮助系统的搜索功能。Lucene 能够为文本类型的数据建立索引,所以你只要能把你要索引的数据格式转化的文本的,Lucene 就能对你的文档进行索引和搜索。比如你要对一些 HTML 文档,PDF 文档进行索引的话你就首先需要把 HTML 文档和 PDF 文档转化成文本格式的,然后将转化后的内容交给 Lucene 进行索引,然后把创建好的索引文件保存到磁盘或者内存中,最后根据用户输入的查询条件在索引文件上进行查询。不指定要索引的文档的格式也使 Lucene 能够几乎适用于所有的搜索应用程序。

ElasticSearch与solr比较

ElasticSearch vs solr 总结

  1. es基本就是开箱使用,非常简单,Solr安装比较复杂一点
  2. Solr支持更多格式的数据,比如json,xml,csv,而ElasticSearch仅支持json文件格式
  3. Solr利用Zookeeper进行分布式管理,而ElasticSearch自身带有分布式协调管理功能。
  4. Solr官方提供的功能更多,而ElasticSearch本身更注重与核心功能,高级功能多有第三方插件提供,例如图形化页面需要kibana友好支撑
  5. Solr查询快,但更新索引满,用于电商等查询多的应用
  6. ElasticSearch建立索引快(查询慢),实时性查询快,用于facebook新浪等搜索
  7. Solr是传统搜索应用的有力解决方案,但ElasticSearch更适用新兴的实时搜索应用
  8. Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而ElasticSearch相对开发维护者较少,更新太快,学习使用成本较高

ElasticSearch安装

声明:JDK1.8,最低要求,ElasticSearch客户端,界面工具 java开发,ElasticSearch的版本和我们之后对应的java的核心jar包!版本对应,JDK环境是正常

下载 https://www.elastic.co/cn/

华为云的镜像去下载 ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?C=N&O=D logstash: https://mirrors.huaweicloud.com/logstash/?C=N&O=D kibana: https://mirrors.huaweicloud.com/kibana/?C=N&O=D

链接: https://pan.baidu.com/s/1xhpIqT8Tm-jN_h2ir9xlwA 提取码: jv4h

  1. 下载后解压
  1. 目录介绍
代码语言:javascript复制
bin  启动文件
config  配置文件
		log4j2 日志配置文件
		jvm.options  java虚拟机相关配置
		elasticsearch.yml  elasticsearch的配置文件  默认9200端口! 跨域!
lib      相关jar包
modules  功能目录
plugins  插件
  1. 双击bin/elasticsearch.bat文件
  1. 访问http://127.0.0.1:9200
  1. 安装可视化界面 ElasticSearch head 下载:https://github.com/mobz/elasticsearch-head
  1. 报错:跨域问题 解决: 打开elasticsearch.yml文件进行配置
代码语言:javascript复制
http.cors.enabled: true
http.cors.allow-origin: "*"
  1. 重新启动elasticSearch和elasticsearch-head

索引:相当于一个数据库

新建一个索引

安装kibana

了解ELK

ELK是elasticSearch、Logstash、kibana三大开源框架首字母大写的简称。市面上也被称为Elastic Stack。其中elasticSearch是一个基于Lucene、分布式、通过RESTful方式进行交互的近实时搜索平台框架。像类似于百度、谷歌这种大数据全文搜索引擎的场景都可以使用elasticSearch作为底层支持框架、可见elasticSearch提供的搜索能力确实强大,elasticSearch也被市面上简称为es。 Logstash是ELK的中央数据引流引擎,用于从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过过滤后支持输出带不同的目的地(文件/MQ/redis/elasticSearch/kafka)等。kibana可以将elasticSearch的数据通过友好的页面展示出来,提供实时分析的功能

下载地址:https://www.elastic.co/cn/downloads/kibana 注意:es版本和kibana版本尽量保持一致

下载完解压

启动测试:bin/kibana.bat

端口:5601 访问:http://localhost:5601

英文看不懂咋办?使用汉化插件

打开/config/kibana.yml文件 设置i18n.locale: “zh-CN”

重新启动kibana

ES核心概念

1、索引 2、字段类型(mapping) 3、文档(documents)

概述 elasticsearch是面向文档,关系型数据库和elasticsearch客观的对比 集群,节点所以,类型,文档,分片,映射是什么?

Relational DB

elasticsearch

数据库(database)

索引(indices)

表(tables)

type

行(rows)

documents

字段(colums)

fieds

elasticsearch(集群)中可以包含多个索引(数据库),每个索引可以包含多个类型(表),每个类型可以包含多个文档(行),每个文档中有保安多个字段(列)。

物理设计: elasticsearch在后台吧每个索引划分成多个分片,每分分片可以在集群中的不同服务器间迁移

逻辑设计: 一个索引类型中,包含多个文档,比如说文档1,文档2。当我们索引一篇文档时,可以通过这样的一个顺序找到它:索引>类型>文档id>,通过这个组合我们就能索引带某个具体的文档。注意:ID不必是整数,实际上是一个字符串

文档

之前说 elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档, elasticsearch中,文档有几个重要属性:

  • 自我包含,一文档同时包含字段和对应的值,也就是同时包含 key: value!name: guangshen
  • 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的
  • 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在 elasticsearch中,对于字 段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。

类型

类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。类型中对于字段的定义称为映射,比如name映射为字符串类型。我们说文档是无模式的,它们不需要拥有映射中所定义的所有字段,比如新增一个字段,那么 elasticsearch是怎么做的呢? elasticsearch会自动的将新字段加入映射,但是这个字段的不确定它是什么类型, elasticsearch就开始猜,如果这个值是18,那elasticsearch会认为它是整形。但是 elasticsearch也可能猜不对,所以最安全的方式就是提前定义好所需要的映射,这点跟关系 型数据库殊途同归了,先定义好字段,然后再使用,别整什么蛾子。

索引

就是数据库! 索引是映射类型的容器, elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上了。我们来研究下分片是如何工作的

物理设计:节点和分片如何工作 一个集群至少有一个节点,而一个节点就是一个 elasricsearch进程,节点可以有多个索引默认的,如果你创建索引,那么索引将会 有个5个分片( primary shard,又称主分片)构成的,毎一个主分片会有一个副本( replica shard,又称复制分片)

上图是一个有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不于丢失。 实际上,一个分片是一个 Lucene索引,一个包含倒排索引的文件目录,倒排素引的结构使得 elasticsearchi在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字。不过,等等,倒排索引是什么鬼?

倒排索引

elasticsearch使用的是一种称为倒排索引的结构,采用 lucene倒排索作为底层。这种结构适用于快速的全文搜索,一个索引由文档中所有不重复的列表构成,对于每一个词,都有一个包含它的文档列表。例如,现在有两个文档,每个文档包含如下内容

代码语言:javascript复制
Study every day , good good up to forever # 文档1包含的内容
To forever  , Study every day, good good up  # 文档2包含的内容

为了创建倒排索引,我们首先要将每个文档拆分成独立的词或称为词条或者 tokens),然后创建一个包含所有不重复的词条的排序列表,然后列出每个词条出现在哪个文档

term

doc_1

doc_2

Study

To

ever

forever

day

study

good

every

to

up

来看一个示例,比如我们通过博客标签来搜索博客文章。那么倒排索引列表就是这样的一个结构

如果要搜索含有 python标签的文章,那相对于査找所有原始数据而言,查找倒排索引后的数据将会快的多。只需要查看标签这栏,然后获取相关的文章ID即可。完全过滤掉无关的所有数据,提高效率!

elasticsearche的索引和 Lucene的索引对比

在 elasticsearcht中,索引这个词被频繁使用,这就是术语的使用。在 elasticsearch中,索引被分为多个分片,每份分片是一个 Lucene的索引。所以一个 elasticsearch素引是由多个 Lucene索引组成的。别问为什么,谁让 elasticsearch使用 Lucene作为底层呢! 如无特指,说起索引都是指 elasticsearchi的索引 接下来的一切操作都在 kibana中 Dev Tools下的 Consale里完成。 基础操作

IK分词器插件

什么是IK分词器

分词:即把一段中文或者別的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,比如“我爱jd”会被分为我",“爱”,“j”,"d”,这显 然是不符合要求的,所以我们需要安装中文分词器K来解决这个问题。

如果要使用中文,建议使用ik分词器 IK提供了两个分词算法: ik smart和 ik max word,其中 ik smart为最少切分, ik max word为最细粒度划分!一会我们测试!

安装

下载地址:https://github.com/medcl/elasticsearch-analysis-ik 下载完毕之后,放入到我们的 elasticsearch插件即可!

通过命令查看插件是否加载:elasticsearch-plugin list

使用kibana测试 查看不同分词器的效果 其中 ik smart为最少切分

ik_max_word为细粒度拆分

自定义词典

  1. 在IK分词器config目录下新建一个*.dic文件

编写自己的词汇

配置到IKAnalyzer.cfg.xml中

重新启动es、kibana

Rest风格说明

一种软件架构风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更筒洁,更有层次,更易于实现缓存等机制。

基本Rest命令说明

method

url地址

描述

PUT

localhost:9200/索引名称/类型名称/文档id

创建文档(指定文档d)

POST

localhost:9200/索引名称/类型名称

创建文档(随机文档id)

POST

locahost:9200/索引名称/类型名称/文档id/_ update

修改文档

DELETE

localhost::9200/索引名称/类型名称/文档id

删除文档

GET

localhost:9200/索引名称/类型名称文档id

查询文档通过文档d

POST

localhost::9200/索引名称/类型名称/_search

查询所有数据

索引的基本操作

运行es,kibana、es-head

创建一个索引
代码语言:javascript复制
PUT /索引名/~类型名~/文档id
{
	请求体
}

完成了自动増加了索引!数据也成功的添加了

那么name这个字段用不用指定类型呢。毕亮我们关系型数据库是需要指定类型的啊 默认类型:

  • 字符串类型:text、keyword
  • 数值类型:ling,integer,short,byte,double,float,half float,scaled float
  • 日期类型:date
  • te布尔值类型:boolean
  • 二进制类型:binary
  • 等等

指定字段的类型

代码语言:javascript复制
PUT /test2
{
  "mappings": {
    "properties": {
     "name":{
       "type": "text"
     },
     "age":{
       "type": "long"
     },
     "birthday":{
       "type": "date"
     }
    }
  }
}
获取索引信息
代码语言:javascript复制
GET /索引名/~类型名~/文档id

如果自己的文档字段没有指定,那么es就会给我们默认配置字段类型

展:通过命令 elasticsearch索引情況!通过get_cat/可以获得es的当前的很多信息!

修改索引状态

POST /索引名称/类型名称/文档名称/_update

代码语言:javascript复制
PUT /test3/_doc/1
{
  "name":"joker",
  "age":18,
  "sex":"男"
}

POST /test3/_doc/1/_update
{
  "doc":{
    "name":"joker_dj"
  }
}
删除索引

通过 DELETE命令实现州除、根据你的请求来判断是删除索引还是删除文档记录!

DELETE /索引名称/类型名称/文档名称

删除指定文档

代码语言:javascript复制
DELETE 索引名称/类型名称/文档id
{
	方法体
}
例:
DELETE test3/_doc/1
{
  "name":"joker_dj"
}

文档的基本操作

基本操作

创建索引

代码语言:javascript复制
PUT /joker/user/1
{
  "name":"joker_dj",
  "age":18,
  "desc":"java小萌新",
  "tags":["技术宅","直男"]
}
PUT /joker/user/1
{
  "name":"joker_dj",
  "age":18,
  "desc":"java小萌新",
  "tags":["技术宅","直男"]
}
PUT /joker/user/3
{
  "name":"李四",
  "age":5,
  "desc":"合伙人",
  "tags":["坏人"]
}
获取文档

GET /索引名称/类型名称/文档id

修改文档

重新put一边就是修改 (不推荐) version就是数据被改动的次数

POST _update,推荐使用这种更新方式

代码语言:javascript复制
POST /索引名称/类型名称/文档id/_update
{
  "doc":{
    "fieds":"value"
  }
}

POST /joker/user/3/_update
{
  "doc":{
    "name":"张三的哥哥李四"
  }
}
文档搜索

简单的搜索

代码语言:javascript复制
GET /索引名称/[类型名称]/[文档id]

高级搜索 条件查询

代码语言:javascript复制
GET /索引名称/[类型名称]/_search?q=fieds:value

复杂操作搜索 select(排序,分页,高亮,模糊査询,精准查询!)

根据_score分数进行排序 查看谁最匹配

代码语言:javascript复制
只要文档中包含value的就会被查出来 前提是被分词器捕获
GET /索引名称/类型名称/_search
{
  "query": {
    "match": {
      "fileds": "value"
    } 
  }
}

GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "张三"
    } 
  }
}

过滤字段

代码语言:javascript复制
GET  /索引名称/类型名称/_search
{
  "query": {
    "match": {
      "fileds": "value"
    }
  },
  "_source": ["fileds","fileds"]
}

GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  },
  "_source": ["desc","name"]
}

排序

代码语言:javascript复制
GET  /索引名称/类型名称/_search
{
  "query": {
    "match": {
      "fileds": "value"
    }
  },
  "_source": ["fileds","fileds"],
  "sort": [
    {
      "fileds": {
        "order": "desc"
      }
    }
  ]
}

例:
GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  },
  "_source": ["desc","name","age"],
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

分页查询

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "match": {
      "name": "张三"
    }
  },
  "from": 0, # 起始值  page
  "size": 20 # 查询大小 pageSize
}

数据下标还是从0开始的,和学的所有数据结构是一样的! /seach/{current}/{pageSize}

布尔查询

多条件查询 must 相当于 and

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "bool": {
     "must ": [
       {
         "match": {
           "name": "张三"
         }
       },
       {
         "match": {
           "age": 5
         }
       }
     ]
    }
  }
}

should相当于 or

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "bool": {
     "should": [
       {
         "match": {
           "name": "张三"
         }
       },
       {
         "match": {
           "age": 5
         }
       }
     ]
    }
  }
}

not操作

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "bool": {
     "must_not": [
       {
         "match": {
           "name": "张三"
         }
       },
       {
         "match": {
           "age": 5
         }
       }
     ]
    }
  }
}

过滤器 filter

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "bool": {
     "must_not": [
       {
         "match": {
           "name": "张三"
         }
       }
     ],
     "filter": {
       "range": {
         "age": {
           "gt": 1, 
         }
       }
     }
    }
  }
}

筛选年龄大于1

  • gt 大于
  • lt 小于
  • gte 大于等于
  • lte 小于等于

匹配多个条件

多个条件之间使用空格隔开 只满足其中一个即可查出 通过分值基本判断

精确查询

term查询是直接通过倒排索引指定的词条进程精确的查找的! 关于分词:

  • term :直接查询精确的
  • match:会使用分词器解析!(先分析文档,然后在通过分析的文档进行查询!)

两个类型 text 、 keyword keyword不会被分词器解析 text 会被分词器解析

多个值匹配的精确查询

高亮查询

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "match": {
      "name":"张三"
    }
  },
  "highlight": {
    "fields": {
      "name":{
        
      }
    }
  }
}

自定义高亮标签

代码语言:javascript复制
GET /joker/user/_search
{
  "query": {
    "match": {
      "name":"张三"
    }
  },
  "highlight": {
    "pre_tags":"<p class='key' style='color:red'>",
    "post_tags":"</p>",
    "fields": {
      "name":{
        
      }
    }
  }
}

集成SpringBoot

官方文档:

https://www.elastic.co/guide/index.html

查看文档

导入maven pom依赖

1、找到原生的依赖

代码语言:javascript复制
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.6.2</version>
</dependency>

2、初始化 用完后关闭客户端

3、分析类中的方法

  1. 创建空的父工程
  1. 创建SpringBoot子模块

勾选相关依赖

下载相关依赖

注意版本问题:要和本地es版本一致,否则可能会出现问题

  1. 新建配置类
代码语言:javascript复制
@Configuration
public class ElasticSearchclientConfig {
    
    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;

    }
}
  1. Api测试
创建索引
代码语言:javascript复制
@SpringBootTest
class ElasticseachApplicationTests {
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    //索引的创建 Request
    @Test
    void testCerateIndex() throws IOException {
        //1. 创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("joker_index");
        //2. 执行创建请求 indices.create
        CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(createIndexResponse);
    }
}
判断索引是否存在
代码语言:javascript复制
    @Test
    void testGetindex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("joker_index");
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }
删除索引
代码语言:javascript复制
//删除索引
    @Test
    void testDeleteindex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("test2");
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.isAcknowledged());
    }
创建添加文档

添加fastjson依赖 方便json转换

代码语言:javascript复制
<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>
代码语言:javascript复制
 //添加文档
    @Test
    void testAddDocument() throws IOException {
        User user = new User("joker_dj", 18);
        //创建请求
        IndexRequest request = new IndexRequest("joker_index");
        // 规则 put joker_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
        //将我们的数据放入请求 json
        request.source(JSON.toJSONString(user), XContentType.JSON);
        //客户端发送请求
        IndexResponse indexRespons = client.index(request, RequestOptions.DEFAULT);
        System.out.println(indexRespons.toString());
        System.out.println(indexRespons.status());
    }
获取文档 判断文档是否存在
代码语言:javascript复制
 //获取文档 判断文档是否存在
    @Test
    void testexitdocument() throws IOException {
        GetRequest request = new GetRequest("joker_index", "1");
        //不获取返回的上下文  _source
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none_");
        boolean exists = client.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }
获取文档的内容
代码语言:javascript复制
//获取文档的内容
    @Test
    void testGetDocument() throws IOException {
        GetRequest request = new GetRequest("joker_index", "1");
        GetResponse documentFields = client.get(request, RequestOptions.DEFAULT);
        System.out.println(documentFields.toString());//打印文档的内容
    }
更新文档内容
代码语言:javascript复制
//更新文档信息
    @Test
    void testUpdateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("joker_index", "1");
        request.timeout("1s");
        User user = new User("joker_djs", 20);
        request.doc(JSON.toJSONString(user),XContentType.JSON);
        UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
        System.out.println(update.status());
    }
删除文档记录
代码语言:javascript复制
 //删除文档记录
    @Test
    void testDeleteRequst() throws IOException {
        DeleteRequest request = new DeleteRequest("joker_index", "1");
        request.timeout("1s");
        DeleteResponse delete = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(delete.status());
    }
批量插入数据
代码语言:javascript复制
 // 批量插入数据
    @Test
    void testBulkRequest() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        ArrayList<User> userList=new ArrayList<>();
        userList.add(new User("joker1",18));
        userList.add(new User("joker2",18));
        userList.add(new User("joker3",18));
        userList.add(new User("joker4",18));
        userList.add(new User("joker5",18));
        userList.add(new User("joker6",18));
        userList.add(new User("joker7",18));
        userList.add(new User("joker8",18));
        for (int i = 0; i < userList.size(); i  ) {
            bulkRequest.add(new IndexRequest("joker_index")
                    .id("" (i 1))
                    .source(JSON.toJSONString(userList.get(i)),XContentType.JSON));
        }
        BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(bulk.hasFailures()); //false 成功
    }
高级查询
代码语言:javascript复制
//查询
    //搜索请求 SearchRequest
    //条件构造 SearchSourceBuilder
    //MatchAllQueryBuilder
    //TermQueryBuilder 精确查询
    // xxx QueryBuilder 
    @Test
    void testSearch() throws IOException {
        SearchRequest searchRequest = new SearchRequest("joker_index");
        //构建搜索条件
        SearchSourceBuilder SourceBuilder = new SearchSourceBuilder();
        //高亮
        SourceBuilder.highlighter();
        //查询条件 我们可以使用QueryBuidler
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "joker1");
//        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        SourceBuilder.query(matchAllQueryBuilder);
        SourceBuilder.timeout(new TimeValue(60,TimeUnit.SECONDS));

        //构建搜索
        searchRequest.source(SourceBuilder);
        /*客户端执行*/
        SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(search.getHits()));
        System.out.println("==============================");
        for (SearchHit hit : search.getHits().getHits()) {
            System.out.println(hit.getSourceAsMap());
        }
    }

实战

项目搭建

  1. 新建一个SpringBoot项目

勾选依赖

引入fastjson

代码语言:javascript复制
 <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.73</version>
        </dependency>

配置文件

引入静态页面

启动访问

爬虫

数据问题?数据库获取,消息队列中获取中,都可以成为数据源,爬虫!

爬取数据:(获取请求返回的页面信息,筛选出我们想要的数据就可以了!)

jsoup
代码语言:javascript复制
<!--解析网页jsoup-->
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.2</version>
        </dependency>
编写解析网页工具包
把爬取到的数据封装成对象
代码语言:javascript复制
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Content {
    private String title;
    private String img;
    private String price;
}
封装工具类
代码语言:javascript复制
public class HtmlParseUtil {
    public static void main(String[] args) throws IOException {
        new HtmlParseUtil().ParseJD(encode).forEach(System.out::println);
    }

    public  List<Content> ParseJD(String keywords) throws IOException {
        //获取请求 :https://search.jd.com/Search?keyword=java
        //需要联网
        String encode = URLEncoder.encode(keywords, "UTF-8");//url字符转义
        String url="https://search.jd.com/Search?keyword="  keywords;
        //解析网页 (Jsoup返回的Document对象就是JS的Document对象)
        Document document = Jsoup.parse(new URL(url), 30000);
        //所有js的方法都可以使用
        Element element = document.getElementById("J_goodsList");
        //获取所有的li标签
        Elements elements = element.getElementsByTag("li");

        ArrayList<Content> goods = new ArrayList<>();
        for (Element el : elements) {
            //关于图片特别多的网站 所有图片都是懒加载
            String img = el.getElementsByTag("img").eq(0).attr("src");//图片
            String price = el.getElementsByClass("p-price").eq(0).text();//价格
            String title = el.getElementsByClass("p-name").eq(0).text();//标题

            Content content = new Content(title, img, price);
            goods.add(content);

        }
        return goods;
    }
}
编写elasticsearch配置类

ElasticSearchclientConfig

代码语言:javascript复制
@Configuration
public class ElasticSearchclientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;

    }
}
创建index索引
创建业务层
代码语言:javascript复制
//业务编写
@Service
public class ContentService {
    @Autowired
    private RestHighLevelClient restHighLevelClient;
    
    //解析数据放入es中
    public boolean parseContent(String keywords) throws IOException {
        List<Content> contents = new HtmlParseUtil().ParseJD(keywords);
        //把查询得到的数据放到es中
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2m");
        for (int i = 0; i < contents.size(); i  ) {
            bulkRequest.add(new IndexRequest("jd_goods")
                    .source(JSON.toJSONString(contents.get(i)), XContentType.JSON));
                    
        }
        BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        return !bulk.hasFailures();
    }
}
编写controller
代码语言:javascript复制
@RestController
public class ContentController {
    @Autowired
    ContentService service;
    @GetMapping("/parse/{keywords}")
    public boolean parse(@PathVariable("keywords") String keywords) throws IOException {
       return service.parseContent(keywords);
    }
}

运行:localhost:9090/parse/java

获取数据实现搜索功能

Service层

代码语言:javascript复制
 //2. 获取数据实现搜索功能
    public List<Map<String,Object>> searchPage(String keywords,int page,int pageSize) throws IOException {
        if(page<=1){
            page=1;
        }
        //条件搜索
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //分页
        sourceBuilder.from(page);
        sourceBuilder.size(pageSize);
	 //模糊匹配
        MatchPhraseQueryBuilder title = QueryBuilders.matchPhraseQuery("title", keywords);
        //精确匹配
       // TermQueryBuilder title = QueryBuilders.termQuery("title", keywords);
        sourceBuilder.query(title);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {
            list.add(hit.getSourceAsMap());
        }
        return list;
    }

Controller

代码语言:javascript复制
   @GetMapping("/search/{keywords}/{page}/{pageSize}")
    public List<Map<String,Object>> search(@PathVariable("keywords") String keywords,@PathVariable("page") int page,@PathVariable("pageSize") int pageSize) throws IOException {
        return  service.searchPage(keywords, page, pageSize);
    }

访问测试

前端渲染数据 vue

下载vue npm install vue npm install axios

引入工程中

编写vue代码

代码语言:javascript复制
<script>
new Vue({
    el:"#app",
    data:{
        keywords:"",//搜索的关键字
        result:[]//搜索的结果
    },
    methods:{
        searchkey(){
            var keyword=this.keywords;
           axios.get("/search/" keyword "/1/10").then(res=>{
               this.result=res.data;
           }).catch(err=>{

           })
        }
    }
})
</script>

数据渲染

实现搜索高亮
代码语言:javascript复制
//3. 获取数据实现高亮搜索功能
    public List<Map<String,Object>> searchHighlightPage(String keywords,int page,int pageSize) throws IOException {
        if(page<=1){
            page=1;
        }
        //条件搜索
        SearchRequest searchRequest = new SearchRequest("jd_goods");
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.requireFieldMatch(false);//是否多个字段高亮;
        highlightBuilder.field("title");//设置高亮的字段
        highlightBuilder.preTags("<span style='color:red'>");//设置前缀
        highlightBuilder.postTags("</span>");//设置后缀
        sourceBuilder.highlighter(highlightBuilder);
        //分页
        sourceBuilder.from(page);
        sourceBuilder.size(pageSize);

        //模糊匹配
        MatchPhraseQueryBuilder titles = QueryBuilders.matchPhraseQuery("title", keywords);
        //精确匹配
        //TermQueryBuilder title = QueryBuilders.termQuery("title", keywords);
        sourceBuilder.query(titles);
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        //执行搜索
        searchRequest.source(sourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //解析结果
        ArrayList<Map<String,Object>> list = new ArrayList<>();
        for (SearchHit hit : search.getHits().getHits()) {

            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();//原来的结果
            //解析高亮的字段
            if(title!=null){
                Text[] fragments = title.fragments();
                String n_title="";
                for (Text text : fragments) {
                    n_title =text;
                }
                sourceAsMap.put("title",n_title);
            }
            list.add(sourceAsMap);
        }
        return list;
    }

contrller引用

访问测试

推荐视频 elasticsearch up主 遇见狂神说: bilibili链接

0 人点赞