官网:Elasticsearch:官方分布式搜索和分析引擎 | Elastic

Elaticsearch,简称为es,es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。es也使用lava开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

据国际权威的数据库产品评测机构DB Engines的统计,在2016年1月,ElasticSearch已超过Solr等,成为排名第一的搜索引擎类应用。

它用于全文搜索结构化搜索分析以及将这三者混合使用

一、ES安装

提前说明:Elaticsearch基于java1.8以上使用 我们需要安装客户端与界面工具 Elaticsearch的版本要与java的jar包依赖对应

解压即可使用
image-20210819183725818
启动elasticsearch.bat 访问 127.0.0.1:9200

安装可视化插件

  1. 安装elasticsearch-head插件(需要Node.js环境)
  2. 解决跨域问题
http.cors.enabled: true
http.cors.allow-origin: "*"

另外,也可以之间安装对应的elasticsearch-head 谷歌插件 不会有跨域问题
image-20210819191503248

了解 ELK

image-20210819191710679

Kibana

Kibana是一个针对Elasticsearch的开源分析及可视化平台,用来搜索、查看交互存储在Elasticsearch索引中的数据。使用Kibana ,可以通过各种图表进行高级数据分析及展示。Kibana让海量数据更容易理解。它操作简单,基于浏览器的用户界面可以快速创建仪表板( dashboard ) 实时显示Elasticsearch查询动态。设置Kibana非常简单。无需编码或者额外的基础架构,几分钟内就可以完成Kibana安装并启动Elasticsearch索引监测。

官网:Kibana:数据的探索、可视化和分析 | Elastic 下载的版本要一致、需要依赖Node环境

解压完成之后 启动kibana.bat 访问 http://localhost:5601
image-20210819194816330
网站默认是英文,更改配置文件

i18n.locale: "zh-CN"

image-20210819195326326
相关工具下载地址

下载慢的小伙伴们可以到 华为云的镜像去下载
速度很快,自己找对应版本就可以
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

至此 工具安装完毕

二、相关概念

elasticsearch是面向文档

关系行数据库和elasticsearch客观的对比!

image-20210820090922861
物理设计∶
elasticsearch在后台把每个索引划分成多个分片,每分分片可以在集群中的不同服务器间迁移
默认的集群名称就是elasticsearch

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

文档

image-20210820091349549

索引

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

如何分片

image-20210820091750002

倒排索引

image-20210820092038963
image-20210820092142014

三、IK分词器

什么是IK分词器?

分词:即把一段中文或者别的划分成一个个的关键字,我们在搜索时候会把自己的信息进行分词,会把数据库中或者索引库中的数据进行分词,然后进行一个匹配操作,默认的中文分词是将每个字看成一个词,不符合要求

IK提供了两个分词算法:ik_ smart和ik_max_word,其中ik smart为最少切分,ik_max_word为最细粒度划分!

  1. 下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
  2. 下载完毕后放入elasticsearch插件中即可 注意版本对应
  3. 启动elasticsearch
    image-20210820093922706
  4. 使用kibana测试
    ik smart为最少切分:
    image-20210820095244028
    ik_max_word为最细粒度划分:
    image-20210820095342011
  5. 有时候分词器不能得出我们想要的,所以需要配置字典
    image-20210820100024716
    我们需要自己配置分词就在自己定义的dic文件中进行配置即可!

四、基本操作

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

创建索引

  1. 创建一个索引
PUT /索引名/类型名()可省略/文档id
{  请求体  }

image-20210820103141687
2. 指定的类型
image-20210820102928445
3. 指定字段的类型

# 创建规则
PUT /test2
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "integer"
      }
    }
  }
}

查看信息

  1. 查看规则
GET test2
  1. 查看默认的信息
PUT /test3/_doc/1
{
  "name": "前度",
  "age": 10
}

GET test3

​ 如果自己的文档字段没有指定,那么es就会给我们默认配置字段类型 另外通过命令elasticsearch索引情况!通过 get _cat/ 可以获得es的当前的很多信息!

修改索引

方法1:提交还是使用PUT即可!然后覆盖!最新办法!

方法2:

POST /test1/type1/1/_update
{
  "doc":{
    "name": "张三"
  }
}

删除索引

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

DELETE test2
  • 简单搜索
GET test1/_search?q=name:前度

_search:代表搜素
?q=xxxx: 搜素条件
  • 复杂搜索

    我们之后使用Java操作es ,所有的方法和对象就是这里面的key !
    image-20210820123424506
    情景2:限制显示的字段信息
    image-20210820123936620
    情景3:排序
    image-20210820124235173
    情景4:分页查询
    image-20210820124550103
    情景5:多条件都满足查询
    image-20210820125735063
    情景6:或(OR)查询
    image-20210820125852895


情景7:精确查询
image-20210820134047585
image-20210820134923972
情景8:高亮显示
image-20210820135557425
我们也能自定义高亮显示样式
image-20210820135946003

五、集成SpringBoot

  1. 导入依赖
         <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>7.6.2</version>
        </dependency>

        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>7.6.2</version>
        </dependency>   
<!--集成SpringBoot只需导入下面这个-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <version>7.6.2</version>
        </dependency>

​ 自定义版本:
image-20210820190136921
2. 构建与关闭
image-20210820185540689
3. 源码
image-20210820192557540
image-20210820192659009
4. 配置

@Configuration
public class ElasticSearchConfig {

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

索引API操作

  1. 创建索引
    @Autowired
    private RestHighLevelClient client;

    //索引的创建 Request
    @Test
    public void creatIndex() throws IOException {
        //1、创建索引请求
        CreateIndexRequest request = new CreateIndexRequest("qiandu_index");
        //2、执行请求->请求后获得响应
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);

        System.out.println(response);
    }
  1. 判断索引是否存在
    //获取索引
    public void existsIndex() throws IOException {
        GetIndexRequest request = new GetIndexRequest("qiandu_index");
        //判断索引是否存在
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
    }
  1. 删除索引
    //删除索引
    public void deleteIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest("qiandu_index");
        //判断索引是否存在
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        //返回true代表删除
        System.out.println(delete.isAcknowledged());
    }

文档API操作

​ 首先需要创建实体类

  1. 添加文档
    //添加文档
    public void addDocument() throws IOException {
        // 创建对象
        User user = new User(1, "qiandu");
        //创建请求
        IndexRequest request = new IndexRequest("qinadu_index");
        //设置规则 PUT /qiandu_index/_doc/1
        request.id("1");
        request.timeout(TimeValue.timeValueSeconds(1));
        
        //将数据放入请求  JSON
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsString(user);
        request.source(s, XContentType.JSON);
        //发送请求,获取响应结果
        IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);
        System.out.println(indexResponse.toString());
        //返回的状态:create/update
        System.out.println(indexResponse.status());
    }
  1. 获取文档,判断是否存在
    //获取文档,判断是否存在 GET qiandu_index/1
    public void existsDocument() throws IOException {
        GetRequest request = new GetRequest("qiandu_index", "1");
        //不获取返回的_source的上下文
        request.fetchSourceContext(FetchSourceContext.DO_NOT_FETCH_SOURCE);
        boolean exists = client.exists(request, RequestOptions.DEFAULT);
        System.out.println(exists);
    }
  1. 获取文档的信息
    //获取文档的信息
    public void getDocument() throws IOException {
        GetRequest request = new GetRequest("qiandu_index", "1");
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        //打印内容 或者用map
        System.out.println(response.getSourceAsString());
        //返回全部内容
        System.out.println(response);
    }
  1. 更新文档信息
    //更新文档信息
    public void updateDocument() throws IOException {
        UpdateRequest request = new UpdateRequest("qindau_index", "1");
        request.timeout("1s"); 
        User user = new User(2, "前度");
        ObjectMapper objectMapper = new ObjectMapper();
        String s = objectMapper.writeValueAsString(user);
        request.doc(s, XContentType.JSON);
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        System.out.println(response.status());
    }
  1. 删除文档
    //删除文档
    public void deleteDocument() throws IOException {
        DeleteRequest request = new DeleteRequest("qinadu_index", "2");
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(response.status());
    }

  1. 批量插入数据
  //批量插入/删除/更新数据
    public void insert() throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("10s");
        ArrayList<User> userList = new ArrayList<>();
        userList.add(new User(1, "前度1"));
        userList.add(new User(2, "前度2"));

        ObjectMapper objectMapper = new ObjectMapper();
        
        for (int i = 0; i < userList.size(); i++) {
            //批量更新/删除也是如此
            bulkRequest.add(
                    new IndexRequest("qiandu_index")
                            .id("" + (i + 1))
                            .source(objectMapper.writeValueAsString(userList.get(i)), XContentType.JSON)
            );
        }
        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        //判断是否执行成功  返回false表示成功
        System.out.println(response.hasFailures());
    }
  1. 查询
    //查询
    public void query() throws IOException {
        SearchRequest request = new SearchRequest("qiandu_index");
        //构建搜索条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //设置高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<p style=' color : red '");
        highlightBuilder.postTags("</p>");
        highlightBuilder.field("name");
        highlightBuilder.requireFieldMatch()
                
        TermQueryBuilder termQuery = QueryBuilders.termQuery("name", "前度");
        sourceBuilder.query(termQuery).highlighter(highlightBuilder);
        //设置超时
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        request.source(sourceBuilder);
        //执行请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //返回的所有数据都在hits中
        System.out.println(response.getHits());
        //打印
        for (SearchHit document : response.getHits().getHits()) {
            //原结果
            System.out.println(document.getSourceAsMap());
            Map<String, HighlightField> highlightFields = document.getHighlightFields();
            //得到高亮的字段
            HighlightField field = highlightFields.get("name");
            //原来的结果
            Map<String, Object> sourceAsMap = document.getSourceAsMap();
            //解析高亮的字段,替换原来的字段
            if (field != null) {
                Text[] fragments = field.fragments();
                String n_field = "";
                for (Text text : fragments) {
                    n_field += text;
                }
                sourceAsMap.put("name", n_field);
            }
            //sourceAsMap放入list中
        }
    }

image-20210820212156082


简单使用

1、
image-20210821125100939
2、
image-20210821125553447


The End~~

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐