ElasticSearch到底是个什么东西

据说微信搜索《Java鱼仔》会变动强!java

本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试均可以看看哦node

(一)介绍

ElasticSearch的目标就是实现搜索。在数据量少的时候,咱们能够经过索引去搜索关系型数据库中的数据,可是若是数据量很大,搜索的效率就会很低,这个时候咱们就须要一种分布式的搜索引擎。Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口git

ES主要用于全文检索、结构化搜索以及分析。ES的应用十分普遍,好比维基百科、Github等都使用ES实现搜索。程序员

(二)核心概念理解

2.1 数据结构

ES既然是用来搜索的,那么它必然也须要存储数据。在Mysql等关系型数据库中,数据的存储遵循下面的逻辑:github

一个数据库(database)中有多个表(tables),每一个表有多行数据(rows),每一行数据由多个字段(columns)组成。web

ES中的存储是这样的:面试

一个索引(indeces)至关于一个数据库(database),每一个索引中有多个类型types(至关于表结构),每一个索引中有多个documents(至关于行),每一个documents由多个fields组成(至关于字段)。算法

你能够把ES理解为他是一个面向文档的数据库。下面用一张图描述ES和关系型数据库之间的类似之处:sql


值得注意的是,在ES7.x版本中,types将慢慢被遗弃,在8.x版本中,types将会完全弃用。数据库

2.2 索引(indeces)和文档(documents)

ES中的索引和Mysql中的索引不是同一种东西,ES中的索引是一个文档的集合,索引就是一个数据库。

前面说了ES是面向文档的,文档是ES中最重要的单位,文档就是一条条的数据。文档中有几个重要的概念:

一、一篇文档中包含多个key:value

二、文档其实就是一个JSON字符串

2.3 分片

咱们经过EShead建立一个索引时,他会让咱们选择分片数量和副本数量

在这里插入图片描述
ES是一个分布式搜索引擎,分片就是把一堆数据分布到多个分片中。而索引是对每一个分片的一个备份,这些副本一样能处理查询请求。

如今假设集群有两个node节点,设置分片数是5个,副本数是1个,那么数据存储结构将变成下面这样,能够保证副本和分片在不一样的节点上:

在这里插入图片描述

2.4 倒排索引

为何ES的搜索这么快,和其中所使用的倒排索引也有必定的关系。倒排索引创建的是分词和文档之间的映射关系。下面经过一个简单的例子来说解一下什么是倒排索引

在这里插入图片描述

原来的数据中咱们经过文档ID去关联标签,可是在查询时就须要遍历全部文档。经过倒排索引,咱们能够经过关键词来找到最匹配的文档。

(三)ES的基本操做

ES是基于Restful风格进行操做的,所以对于习惯了写crud的程序员来讲,ES很容易上手。ES的操做可使用Kibana,也可使用Postman直接调用,由于归根结底它就是一个restful的操做。我这里使用Idea的ES插件直接调用。
3.1 建立文档

PUT http://ip:port/索引名/类型名/文档id

{ 
 
  
    "key":"value"
}

由于类型名在后续的版本中将会被删除,这里能够用_doc表明默认类型:

PUT http://ip:port/索引名/_doc/文档id

下面给出操做截图

经过put建立一个索引以后,咱们能够在head中看到对应的数据

3.2 建立带有数据类型的索引

3.1中建立数据时,没有指定具体的数据类型,咱们固然也能够为索引指定数据类型

PUT http://ip:port/索引名
参数示例:
{ 
 
  
  "mappings": { 
 
  
    "properties": { 
 
  
      "name": { 
 
  
        "type": "text"
      },
      "address": { 
 
  
        "type": "text"
      }
    }
  }
}

ES中的核心数据类型以下:

1)字符串类型: text, keyword
(2)数字类型:long, integer, short, byte, double, float, half_float, scaled_float
(3)日期:date
(4)日期 纳秒:date_nanos
(5)布尔型:boolean6)Binary:binary
(7)Range: integer_range, float_range, long_range, double_range, date_range

3.3 查看索引或者文档的数据

经过GET请求能够查看索引以及文档的信息:

GET http://ip:port/索引名   #查看索引
GET http://ip:port/索引名/类型名/文档ID  #查看文档

3.4 修改数据

修改数据和建立数据同样,经过PUT操做就会更新原来的数据:

PUT http://ip:port/索引名/类型名/文档id
{ 
 
  
    "key":"value"
}

若是是修改的话,响应结果中的version就会增长。

另一种方法是使用Post请求:

POST http://ip:port/索引名/类型名/文档id/_update
参数实例:
{ 
 
  
  "doc": { 
 
  
    "name": "javayz4"
  }
}

更推荐使用这种方式,若是使用PUT方法忘了加某个key,更新就会变成新增

3.5 删除数据

经过DELETE的方式删除数据

DELETE http://ip:port/索引名/类型名/文档id  #删除具体的文档
DELETE http://ip:port/索引名  #删除索引

(四)ES的搜索操做

ES最重要的就是它的搜索操做了。

4.1 简单搜索

直接将搜索的参数带到连接中:

GET http://ip:port/索引名/_search?q=key:value

结果以下:

4.2 经过param传递参数

除了将参数放到连接当中,还能够将参数经过JSON请求体的方式传递,其中from和size是分页的参数query中传递查询条件_source表示结果中要展现的列,不写就表示展现全部。

GET http://ip:port/索引名/_search
参数示例:
{ 
 
  
  "from": 0,
  "size": 20,
  "query": { 
 
  
    "match": { 
 
  
      "name": "javayz2"
    }
  },
  "_source": ["name","address"]
}

除了上面示例中的这些参数以外,还有不少参数可使用,好比排序

"sort": [
  { 
 
  
    "age": { 
 
  
      "order": "desc"
    }
  }
]

多条件查询:must表示下面的两个条件都要知足,还能够填should,表示任意知足其中一个条件便可,或者是must_not,表示must的相反值

"query": { 
 
  
    "bool": { 
 
  
      "must": [
        { 
 
  
          "match": { 
 
  
            "name": "javayz"
          }
        },
        { 
 
  
          "match": { 
 
  
            "address": "hz"
          }
        }
      ]
    }
}

若是你的数据中存在集合,能够经过空格对多个条件进行查询:


查询过程当中还支持高亮查询

"highlight":{ 
 
  
  "pre_tags": "<em>",
  "post_tags": "</em>",
  "fields": { 
 
  
    "name": { 
 
  }
  }
}

(五)分词器

所谓分词器,就是将一段话分红一个个关键字,搜索时就按照这些关键字进行搜索。比较好用的分词器有中文的IK分词器。

5.1 基本使用

给出下载连接:https://github.com/medcl/elasticsearch-analysis-ik/releases

下载和本身ES相同的版本,在plugin目录下新建一个ik文件夹,将下载的文件解压到ik目录下,从新启动便可。

IK分词器提供了两种算法:

一、ik_smart:最少切分

二、ik_max_word:最细粒划分

首先最少切分是根据字典给出最少的切分:


ik_max_word是最细粒划分,他会给出最多的结果:

{ 
 
  
  "analyzer": "ik_max_word",
  "text": "我是Java工程师"
}

结果:

{ 
 
  
  "tokens": [
    { 
 
  
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    { 
 
  
      "token": "是",
      "start_offset": 1,
      "end_offset": 2,
      "type": "CN_CHAR",
      "position": 1
    },
    { 
 
  
      "token": "java",
      "start_offset": 2,
      "end_offset": 6,
      "type": "ENGLISH",
      "position": 2
    },
    { 
 
  
      "token": "工程师",
      "start_offset": 6,
      "end_offset": 9,
      "type": "CN_WORD",
      "position": 3
    },
    { 
 
  
      "token": "工程",
      "start_offset": 6,
      "end_offset": 8,
      "type": "CN_WORD",
      "position": 4
    },
    { 
 
  
      "token": "师",
      "start_offset": 8,
      "end_offset": 9,
      "type": "CN_CHAR",
      "position": 5
    }
  ]
}

5.2 字典

对于一些名词,IK自带的字典没法区分,好比个人博客名Java鱼仔,它分词后是这样的:

所以咱们须要手动去增长这样的字典,IK目录下的config/IKAnalyzer.cfg.xml中能够添加本身的字典,首先我在config下新建一个my.dic文件,里面的词汇如今只写了一个Java鱼仔。而后在配置文件中配置本身的my.dic

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户能够在这里配置本身的扩展字典 -->
        <entry key="ext_dict">my.dic</entry>
         <!--用户能够在这里配置本身的扩展中止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户能够在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户能够在这里配置远程扩展中止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

重启后再次进行分词,结果以下:

若是字典没法被识别,多是格式等问题。

(六)总结

这篇文章主要对ES的概念以及基本的操做进行讲解,项目中使用时咱们会将ES集成到Springboot中。本期的分享就到这了,我是鱼仔,咱们下期再见!