• elasticsearch


    elasticsearch安装

    有些软件对于安装路径有一定的要求,例如:路径中不能有空格,不能有中文,不能有特殊符号,等等。

    为了避免不必要的麻烦,也懒得一一辨别踩坑,我们人为作出「统一的约定」:

    • 解压版的软件,一律安装在:D:\ProgramFiles 。这是一个没中文、没空格的路径!

    Elasticsearch 只有解压版本,没有安装版

    Elastic 官网:https://www.elastic.co/cn/

    image-20210607091331235

    Elastic 有一条完整的产品线及解决方案:Elasticsearch、Kibana、Logstash 等,前面说的三个就是大家常说的 ELK 技术栈。

    image-20210607091413787

    Elasticsearch 具备以下特点:

    • 分布式,无需人工搭建集群(solr 就需要人为配置,使用 Zookeeper 作为注册中心);
    • Restful 风格,一切 API 都遵循 Restful 原则,容易上手;
    • 近实时搜索,数据更新在 Elasticsearch 中几乎是完全同步的。

    kibana 从 7.11 开始升级了 node.js 的版本,因此,从这个版本开始不再支持 win7,也就是说,win7 能使用的 kibana 的最后的版本是 7.10.2

    1. 安装 Elasticsearch

    1.1 下载解压

    1675039188878

    1.2 配置

    本步骤是可选操作:如果机子内存足够大也可以不改配置

    我们进入 elasticsearch-7.11.1/config 目录:

    需要修改的配置文件有两个:

    • elasticsearch.yml
    • jvm.options
    1.2.1 jvm.options

    Elasticsearch 基于 Lucene 的,而 Lucene 底层是 java 实现,若本机内存不够需要配置 jvm 参数。

    在jvm.options.d文件下创建配置文件(文件后缀是options即可)例如heap.options

    • 内存占用太多了,我们调小一些:

      -Xms512m
      -Xmx512m
      
      • 1
      • 2
    1.2.2 elasticsearch.yml

    elasticsearch.yml 配置文件暂时不用改动。

    1.3 运行

    进入 elasticsearch-7.11.1\bin 目录

    双击 elasticsearch.bat,启动成功时,会显示 started 字样,并且可我们在浏览器中访问:http://127.0.0.1:9200,可见类似如下内容:

    {
      "name" : "DESKTOP-T540P",
      "cluster_name" : "elasticsearch",
      "cluster_uuid" : "XvelzExUQgud2iqO9QLA4w",
      "version" : {
        "number" : "7.11.1",
        "build_flavor" : "default",
        "build_type" : "zip",
        "build_hash" : "747e1cc71def077253878a59143c1f785afa92b9",
        "build_date" : "2021-01-13T00:42:12.435326Z",
        "build_snapshot" : false,
        "lucene_version" : "8.7.0",
        "minimum_wire_compatibility_version" : "6.8.0",
        "minimum_index_compatibility_version" : "6.0.0-beta1"
      },
      "tagline" : "You Know, for Search"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2. elasicsearch 概念

    2.1数据分类和查询方式

    我们生活中的数据总体分为两种:

    #数据类型说明
    1结构化数据指具有固定格式或有限长度的数据,如数据库,元数据等。
    2非结构化数据指不定长或无固定格式的数据,如邮件,word文档等磁盘上的文件
    • 结构化数据的查询方式

    最常见的结构化数据也就是数据库中的数据。

    结构化数据很容易查询,因为结构化的数据存储是有规律的。以数据库数据为例,它们有行,有列,有格式/类型,连数据的长度都是固定的。

    非结构化数据的查询方式

    • 顺序扫描法(Serial Scanning)

      想象一下你在 Word 文档中使用 Ctrl + f 进行搜索。

      所谓顺序扫描,比如要找内容包含某一个字符串的文件,就是一个文档一个文档的看,对于每一个文档,从头看到尾,如果此文档包含此字符串,则此文档为我们要找的文件,接着看下一个文件,直到扫描完所有的文件。

      这个过程是相当慢的。

    • 全文检索(Full-text Search

      将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引

      从非结构化数据中提取出来的信息,通常也就是你所关注的核心信息,或者是搜索关键字。

      例如:字典。字典有两套索引:拼音表和部首检字表。拼音表就是提取的各个文字的读音信息而组成的索引;部首检字表就是提取的各个文字的偏旁部首信息而组成的索引。

      Note:一份非结构化数据,可以不止有一份索引。
      
      • 1

      这种先建立索引,再对索引进行搜索的过程就叫全文检索(全文检索通常使用倒排索引来实现)(Full-text Search)。

      正排索引和倒排索引区别

      正排索引:由key查询实体的过程,使用正排索引

      倒排索引:与正排索引相反,由item查询key的过程,使用倒排索引

      举个例子

      举个例子,假设有3个网页:
      url1 -> “我爱北京”
      url2 -> “我爱到家”
      url3 -> “到家美好”
      这是一个正排索引:
      Map结构如下
      分词之后:
      url1 -> {我,爱,北京}
      url2 -> {我,爱,到家}
      url3 -> {到家,美好}
      这是一个分词后的正排索引:
      
      分词后倒排索引:
      Map结构如下
      我 -> {url1, url2}
      爱 -> {url1, url2}
      北京 -> {url1}
      到家 -> {url2, url3}
      美好 -> {url3}
      由检索词item快速找到包含这个查询词的网页Map就是倒排索引
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20

      虽然创建索引的过程也是非常耗时的,但是索引一旦创建就可以多次使用,全文检索主要处理的是查询,所以耗时间创建索引是值得的。

    2.2 全文检索

    可以使用 Lucene 实现全文检索。Lucene 是 apache 下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。

    Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。

    Lucene 只是一个库(类似于汽车发动机),而非独立的产品。通过 Lucene 实现搜索功能,但你仍需作大量的其他的工作。Solr 和 ElasticSearch 都是基于 Lucene 的搜索引擎产品。

    对于数据量大、数据结构不固定的数据可采用全文检索方式搜索,比如百度、Google 等搜索引擎、论坛站内搜索、电商网站站内搜索等

    3. elasticsearch简介

    Elasticsearch 是一个基于 Lucene 的搜索服务器,它采用 Java 语言编写,使用 Lucene 构建索引、提供搜索功能,并以 Apache 许可条款发布。

    Elasticsearch 对外提供了 RESTful API ,以使你能通过多种形式操作它。

    Elasticsearch 的优点

    • 分布式
    • 全文检索
    • 近实时搜索和分析
    • 高可用
    • RESTful API

    3.1 核心概念

    你完全可以将 Elasticsearch 当作一个数据库(NoSQL)来看待,以便于你的理解,也更方便与你通过现象看到它的本质。实际上在很多使用场景中,Elasticsearch 确实就是在扮演 NoSQL 数据库的角色。

    类似于数据库的层次结构,Elastic Search 也是如此:

    mysql               es
    └── database        └── index
        └── table           └── type
            └── row             └── document
    
    • 1
    • 2
    • 3
    • 4
    另外,在 SQL 数据库中被我们称作『列』的东西,实际上也被称作『字段』,只不过我们更习惯于使用前者。而 Elastic Search(和 Lucene)则是使用后一种称呼。
    
    • 1

    3.2 概念的弱化

    虽然和 RDMS(关系型数据库) 中的概念有一一对应的关系,但是 Elasticsearch 正在一步步弱化 type 的概念,并计划在未来移除 type 这个概念。

    这种情况下就类似于,数据库中人为约定:一个 database 里默认有且仅有一个 table 。此时,这个 table 叫什么,实际上就无关紧要了。即便是有这样的奇怪的约定,但是实际上仍不影响我们使用 MySQL,因为你仍然可以建多个 database 。

    • 6.0 的时候,已经默认只能支持一个索引中有且仅有一个 type 了;
    • 到了 7.0 的时候,如果你在命令中指定 type 时,Elasticsearch 会提示你 type 被废弃(deprecated),建议使用 _doc 关键字替代。
    • 更有甚至,很多原来需要填写 type-name 的地方,不仅仅是可以使用 _doc 替代,甚至连 _doc 都不用出现都是 ok 的。

    3.3 es的restful风格api

    Elastic Search 的一个特点就是对外提供 Restful API 来对其进行操作,因此,它直接利用 HTTP 的四种不同请求方式来表示当前操作是增删改查中的哪一种。

    HTTP 请求方式操作
    POST新增操作,类似于 INSERT
    DELETE删除操作,类似于 DELETE
    PUT修改操作,类似于 UPDATE
    GET查询操作,类似于 SELECT

    3.4 ES 中的数据类型

    和数据库中的字段(列)有数据类型的概念一样,ElasticSearch 中 document 的每个『字段』也有数据类型的概念。ElasticSearch 支持的数据类型有:

    • 字符串型:text,keyword

      text 会被分词器分词;keyword 不会被分词器分词

    • 数字:long, integer, short, double, float

    • 日期:date

    • 逻辑:boolean

    再复杂一些的数据类型有:

    • 对象类型:object
    • 数组类型:array
    • 地理位置:geo_point,geo_shape

    3.5 其它

    和数据库一样,Elastic Search 也有 集群、节点、分片、备份的概念。

    另外,Elasticsearch 流行的原因之一就是其内置了集群功能,即它本身『天生』就是分布式的。即便你在单机上只有一个节点,Elasticsearch 也将它当做一个集群来看待。默认也会对你的数据进行分片和副本操作,当你向集群添加新数据时,数据也会在新加入的节点中进行平衡。

    4. 对ElasticSearch 操作

    4.1 操作索引

    4.1.1 创建索引

    对比关系型数据库,创建索引就等于创建数据库。

    在postman 中,向ES服务器发送PUT 请求:http://127.0.0.1:9200/shopping

    4.1.2 查询索引

    在postman 中,向ES服务器发送GET请求:http://127.0.0.1:9200/shopping

    查看ES 中所有索引 ,向ES服务器发送GET请求:http://127.0.0.1:9200/_cat/indices?v

    4.1.3 删除索引

    向ES服务器发送DELETE 请求:

    http://127.0.0.1:9200/shopping
    
    • 1

    4.2 操作文档

    4.2.1 创建文档映射(类似建字段,类型)
    post  http://127.0.0.1:9200/shopping/_mapping
    请求体
    {
    "properties":{
    	"title":{
    		"type":"keyword",
    		"index":true
    	},
    	"category":{
    		"type":"text",
    		"index":true
    	},
    	"image":{
    		"type":"keyword",
    		"index":false
    	},
    	"price":{
    		"type":"keyword",
    		"index":false
    	}
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    4.2.2 创建文档

    在postman 中,向ES服务器发送POST 请求:

    http://127.0.0.1:9200/shopping/_doc
    
    • 1

    请求体

    {
    "title":"小米手机",
    "category":"小米",
    "image":"http://127.0.0.1/9000/phone/1111.jpg",
    "price":3333.00
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    此时的请求会给这个文档自动生成一个id

    指定id生成文档

    向ES服务器发送PUT 请求:

    http://127.0.0.1:9200/shopping/_doc/1001
    
    • 1

    请求体

    {
    "title":"小米手机",
    "category":"小米",
    "image":"http://127.0.0.1/9000/phone/1111.jpg",
    "price":3333.00
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    4.2.3 查看文档

    向ES服务器发送GET 请求:

    http://127.0.0.1:9200/shopping/_doc/1001
    
    • 1

    向ES服务器发送GET 请求:

    http://127.0.0.1:9200/shopping/_doc/1001/_source
    
    • 1

    查询索引下所有文档数据,向ES服务器发送GET 请求:

    http://127.0.0.1:9200/shopping/_doc/_search
    
    • 1
    4.2.4 条件查询文档
    post http://127.0.0.1:9200/shopping/_doc/_search
    请求体
    {
        "query":{
            "match":{
                "title":"小米手机1"
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    4.2.5 删除文档

    向ES服务器发送DELETE请求:

    http://127.0.0.1:9200/shopping/_doc/{文档Id}
    
    • 1

    5. Spring Boot 集成 ElasticSearch

    
        org.springframework.boot
        spring-boot-starter-data-elasticsearch
    
    
    • 1
    • 2
    • 3
    • 4
    • 老版本配置方式(已被废弃,不再推荐使用)

      略。

    • 新版本配置方式(推荐使用)

      新的配置方式使用的是 High Level REST Client 的方式来替代之前的 Transport Client 方式,使用的是 HTTP 请求,和 Kibana 一样使用的是 Elasticsearch 的 9200 端口。

      这种配置方案中,你使用的不是配置文件,而是自定义配置类:

      /**
       * 你也可以不继承 AbstractElasticsearchConfiguration 类,而将 ESConfig 写成一般的配置类的型式。
       * 不过继承 AbstractElasticsearchConfiguration 好处在于,它已经帮我们配置好了 elasticsearchTemplate 直接使用。
       */
      @Configuration
      public class ESConfig extends AbstractElasticsearchConfiguration {
      
          @Override
          public RestHighLevelClient elasticsearchClient() {
              ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                  .connectedTo("localhost:9200")
                  .build();
              return RestClients.create(clientConfiguration).rest();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15

    Elasticsearch 中的 PO 类:

    @Document(indexName = "books", shards = 1, replicas = 0)
    @Data
    public class Book {
    
        @Id
        @Field(type = FieldType.Integer)
        private Integer id;
        @Field(type = FieldType.Keyword)
        private String title;
        @Field(type = FieldType.Text)
        private String press;
        @Field(type = FieldType.Keyword)
        private String author;
        @Field(type = FieldType.Keyword,index=false)
        private BigDecimal price;
        @Field(type = FieldType.Text)
        private String description;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • @Document :注解会对实体中的所有属性建立索引;
    • indexName = “books” :表示创建一个名称为 “books” 的索引;
    • shards = 1 : 表示只使用一个分片;
    • replicas = 0 : 表示不使用复制备份;
    • index = false: 不能索引查询
    • @Field(type = FieldType.Keyword) : 用以指定字段的数据类型。

    4.1 创建操作的 Repository

    @Repository
    public interface BookRepository extends ElasticsearchRepository<Book, String> {
    
    }
    
    • 1
    • 2
    • 3
    • 4

    spring-boot-es-02

    我们自定义的 CustomerRepository 接口,从它的祖先们那里继承了大量的现成的方法,除此之外,它还可以按 spring data 的规则定义特定的方法。

    4.2 测试 CustomerRepository

    // 创建索引
    @Test
    public void indexList() {
       System.out.println("创建索引");
    }
    // 删除索引
    @Test
    public void indexList() {
    	restTemplate.indexOps(IndexCoordinates.of("books")).delete();
        System.out.println("删除索引");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    6. CRUD操作

    5.1、批量新增

    @Test
    public void indexList() {
       List lists = new ArrayList<>();
       lists.add(new BookPo("2","java 程序设计","小孔明",45.4F,
                            "java 语言","2033-03-03","一本好书"));
       lists.add(new BookPo("3","java 编程思想","小孔明",45.4F,
                            "java 语言","2033-03-03","一本好书"));
       lists.add(new BookPo("4","java 逻辑","小孔明",45.4F,
                            "java 语言","2033-03-03","一本好书"));
       lists.add(new BookPo("5","java 面向对象","小孔明",45.4F,
                            "java 语言","2033-03-03","一本好书"));
    
       bookEsDao.saveAll(lists);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5.2、修改

    修改和新增是同一个接口,区分的依据就是id,这一点跟我们在页面发起PUT请求是类似的。

    BookPo bookPo = new  BookPo("5","java 程序设计","小孔明","java 语言",
            45.4F,"2016-03-03","很好");
    booksEsDao.save(bookPo);  
    //由于上面的id = 5 已经存在,故再次save 就是修改
    
    • 1
    • 2
    • 3
    • 4

    5.3、删除

    @Test
    public void test2(){
        bookEsDao.deleteById("1");
        bookEsDao.deleteAll();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5.4、基本查询

    1、ElasticsearchRepository提供了一些基本的查询方法:

    @Test
    public void testQuery(){
        Optional optional = this.bookEsDao.findById("1");
        System.out.println(optional.get());
    }
    
    @Test
    public void testFind(){
        // 查询全部,并按照价格降序排序
         //写法一: 
        Iterable items = this.bookEsDao.findAll(Sort.by(Sort.Direction.DESC,
                        "price"));
        //写法二: 
        Iterable items = this.booksEsDao.findAll(Sort.by(Sort.Order.desc("price")));
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2、分页查询

    Spring Data 自带的分页方案:

    @Test
    public  void testByPage(){
         	Sort sort = Sort.by(Sort.Direction.ASC,"id");
            //分页
            PageRequest pageRequest = PageRequest.of(0,2,sort);
            Page all = productDao.findAll(pageRequest);
            for (Product product : all) {
            System.out.println(product);
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、自定义方法查询

    Spring Data 的另一个强大功能,是根据方法名称自动实现功能。

    比如:你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。

    当然,方法名称要符合一定的约定

    KeywordSampleElasticsearch Query String
    AndfindByNameAndPrice{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
    OrfindByNameOrPrice{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}}
    IsfindByName{"bool" : {"must" : {"field" : {"name" : "?"}}}}
    NotfindByNameNot{"bool" : {"must_not" : {"field" : {"name" : "?"}}}}
    BetweenfindByPriceBetween{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
    LessThanEqualfindByPriceLessThan{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
    GreaterThanEqualfindByPriceGreaterThan{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
    BeforefindByPriceBefore{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}}
    AfterfindByPriceAfter{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}}
    LikefindByNameLike{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
    StartingWithfindByNameStartingWith{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}}
    EndingWithfindByNameEndingWith{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}}
    Contains/ContainingfindByNameContaining{"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}}
    InfindByNameIn(Collectionnames){"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}}
    NotInfindByNameNotIn(Collectionnames){"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}}
    NearfindByStoreNearNot Supported Yet !
    TruefindByAvailableTrue{"bool" : {"must" : {"field" : {"available" : true}}}}
    FalsefindByAvailableFalse{"bool" : {"must" : {"field" : {"available" : false}}}}
    OrderByfindByAvailableTrueOrderByNameDesc{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}}

    如:

    public interface EsBooksDao extends ElasticsearchRepository{
        public List findBookPoByAuthor(String author);
        public List findBookPoByTitleAndPrice(String title,float price);
        List findByPriceBetween(float price1, float price2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7. es场景

    场景一:对外暴露的数据(数据量大的)的用es,如果不需要对外暴露,不需要全文检索的话,那么直接从数据查,所以做项目分析数据分成2块(哪些数据需要放es,从es查,哪些不需要)

    vailable" : false}}}} | |OrderBy |findByAvailableTrueOrderByNameDesc |{“sort” : [{ “name” : {“order” : “desc”} }],“bool” : {“must” : {“field” : {“available” : true}}}}` |

    如:

    public interface EsBooksDao extends ElasticsearchRepository{
        public List findBookPoByAuthor(String author);
        public List findBookPoByTitleAndPrice(String title,float price);
        List findByPriceBetween(float price1, float price2);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    7. es场景

    场景一:对外暴露的数据(数据量大的)的用es,如果不需要对外暴露,不需要全文检索的话,那么直接从数据查,所以做项目分析数据分成2块(哪些数据需要放es,从es查,哪些不需要)

    场景二:作为mysql的外置索引,把作为数据库查询条件的列数据放到es里面,这样在查询的时候,先从es查询出符合条件的id,然后根据id去数据库查,数据维护大,一旦es宕机,就麻烦了

  • 相关阅读:
    跟运维学 Linux - 01
    C#语言实例源码系列-实现批量给图片添加水印
    Mediapipe Android环境搭建
    【Python基础入门6】Python的输入与运算符
    python多线程、进程
    模板引擎小结-原理
    RadonDB MySQL Kubernetes 2.2.1 发布!
    Swift新async/await并发模型中子任务取消不能被其它子任务感知的原因及解决
    openvino学习(一)ubuntu20.04安装openvino2022
    Spring Boot企业级开发教程课后习题——第1章Spring Boot开发入门
  • 原文地址:https://blog.csdn.net/SurepMan/article/details/132828581