全文搜索引擎 Elasticsearch 入门教程

本章章节目录:

   1. Elasticsearch介绍:

   2. Elasticsearch Windows安装;

   3. Elasticsearch 核心概念;

   4. Elasticsearch 基础API; 

 1. Elasticsearch介绍:

       全文搜索属于最常见的需求,开源的 Elasticsearch (以下简称 Elastic)是目前全文搜索引擎的首选。

       它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。

        Elastic 的底层是开源库 Lucene。但是,你没法直接用 Lucene,必须自己写代码去调用它的接口。Elastic 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。

        本文从零开始,讲解如何使用 Elastic 搭建自己的全文搜索引擎。每一步都有详细的说明,大家跟着做就能学会。

 2. Elasticsearch Windows安装;

        Elastic 需要 Java 8 环境。如果你的机器还没安装 Java,注意要保证环境变量JAVA_HOME正确设置。

        安装完 Java,就可以跟着官方文档安装 Elastic。直接下载压缩包比较简单。

         在官网下载压缩包,解压后直接运行bin目录下的.bat文件即可。下载地址戳这里。

    我的版本:

          elasticsearch-5.2.0.zip

          kibana-5.2.0-windows-x86.zip

      Windows直接解压启动就行了;

      检查ES是否启动成功:http://localhost:9200/?pretty

{
  "name" : "LBqzCrj",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "LO8VkQ0WSlucfjevxNhWKw",
  "version" : {
    "number" : "5.2.0",
    "build_hash" : "24e05b9",
    "build_date" : "2017-01-24T19:52:35.800Z",
    "build_snapshot" : false,
    "lucene_version" : "6.4.0"
  },
  "tagline" : "You Know, for Search"
}

name: node名称

cluster_name: 集群名称(默认的集群名称就是elasticsearch)

version.number: 5.2.0,es版本号

ES配置集群

  Elasticsearch配置集群很简单,只要配置一个集群的 名称 ,ES就会自动寻找并加入到其中。

  并且会自动的进行分片、备份等等操作。

   配置方式:

  直接修改conf/elasticsearch.yml

       image.png

    ES查询集群状态

  使用ES的REST API可以做到下面的事情:

  1 管理集群,节点,索引数据和元数据

  2 执行创建,读取,更新和删除操作,以及根据索引查询

  3 执行更深入的操作,比如分页、排序、过滤、脚本、faceting、聚合等。

      本系列的文章都是采用kibana-5.2.0 操作的:

         http://localhost:5601/app/kibana#/management/kibana/index

     查询集群的健康状况:

          GET /_cat/health?v

      显示:

        epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent

     1515596396 22:59:56  elasticsearch yellow          1         1     34  34    0    0       34             0                  –                 50.0%

  查询结果中status会显示状态颜色:

  red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了

  yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态

  green:每个索引的primary shard和replica shard都是active状态的

  注意,即便是红色,部分分片上的数据也是可用的。

  为什么现在会处于一个yellow状态?

          我们现在就一个笔记本电脑,就启动了一个es进程,相当于就只有一个node。现在es中有一个index,就是kibana自己内置建立的index。由于默认的配置是给每个index分配5个primary shard和5个replica shard,而且primary shard和replica shard不能在同一台机器上(为了容错)。现在kibana自己建立的index是1个primary shard和1个replica shard。当前就一个node,所以只有1个primary shard被分配了和启动了,但是一个replica shard没有第二台机器去启动。

       做一个小实验:此时只要启动第二个es进程,就会在es集群中有2个node,然后那1个replica shard就会自动分配过去,然后cluster status就会变成green状态。

3. Elasticsearch 核心概念;

  (1)Near Realtime(NRT):近实时,两个意思,从写入数据到数据可以被搜索到有一个小延迟(大概1秒);基于es执行搜索和分析可以达到秒级

  (2)Cluster:集群,包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常

  (3)Node:节点,集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群

  (4)Document&field:文档,es中的最小数据单元,一个document可以是一条客户数据,一条商品分类数据,一条订单数据,通常用JSON数据结构表示,每个index下的type中,都可以去存储多个document。一个document里面有多个field,每个field就是一个数据字段。

product document
{
  "product_id": "1",
  "product_name": "高露洁牙膏",
  "product_desc": "高效美白",
  "category_id": "2",
  "category_name": "日化用品"
}

    (5)Index:索引,包含一堆有相似结构的文档数据,比如可以有一个客户索引,商品分类索引,订单索引,索引有一个名称。一个index包含很多document,一个index就代表了一类类似的或者相同的document。比如说建立一个product index,商品索引,里面可能就存放了所有的商品数据,所有的商品document。

    下面的命令可以查看当前节点的所有 Index。

         GET /_cat/indices?v

(6)Type:类型,每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field,比如博客系统,有一个索引,可以定义用户数据type,博客数据type,评论数据type。

     下面的命令可以列出每个 Index 所包含的 Type:

        GET /_mapping?pretty=true

     商品index,里面存放了所有的商品数据,商品document

     但是商品分很多种类,每个种类的document的field可能不太一样,比如说电器商品,可能还包含一些诸如售后时间范围这样的特殊field;生鲜商品,还包含一些诸如生鲜保质期之类的特殊field

type,日化商品type,电器商品type,生鲜商品type

日化商品type:product_id,product_name,product_desc,category_id,category_name

电器商品type:product_id,product_name,product_desc,category_id,category_name,service_period

生鲜商品type:product_id,product_name,product_desc,category_id,category_name,eat_period

每一个type里面,都会包含一堆document

{
  "product_id": "2",
  "product_name": "长虹电视机",
  "product_desc": "4k高清",
  "category_id": "3",
  "category_name": "电器",
  "service_period": "1年"
}
{
  "product_id": "3",
  "product_name": "基围虾",
  "product_desc": "纯天然,冰岛产",
  "category_id": "4",
  "category_name": "生鲜",
  "eat_period": "7天"
}

(7)_id元数据:

    代表document的唯一标识,与index和type一起,可以唯一标识和定位一个document

    我们可以手动指定document的id(put /index/type/id),也可以不指定,由es自动为我们创建一个id ;

     1、手动指定document id

      put /index/type/id

     2、自动生成document id

     POST /test_index/test_type {}

(8)shard:单台机器无法存储大量数据,es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个shard都是一个lucene index。

4. Elasticsearch 基础API;

    ES支持近实时的索引、更新、查询、删除文档,近实时就意味着刚刚索引的数据需要1秒钟后才能搜索到,这也是与传统的SQL数据库不同的地方。

    ElasticSearch的对象模型,跟关系型数据库模型相比:

       索引(Index):相当于数据库,用于定义文档类型的存储;在同一个索引中,同一个字段只能定义一个数据类型;

       文档类型(Type):相当于关系表,用于描述文档中的各个字段的定义;不同的文档类型,能够存储不同的字段,服务于不同的查询请求;

       文档(Document):相当于关系表的数据行,存储数据的载体,包含一个或多个存有数据的字段;

       字段(Field):文档的一个Key/Value对;

       词(Term):表示文本中的一个单词;

       标记(Token):表示在字段中出现的词,由该词的文本、偏移量(开始和结束)以及类型组成;

       索引是由段(Segment)组成的,段存储在硬盘(Disk)文件中,段不是实时更新的,这意味着,段在写入磁盘后,就不再被更新。ElasticSearch引擎把被删除的文档的信息存储在一个单独的文件中,在搜索数据时,ElasticSearch引擎首先从段中查询,再从查询结果中过滤被删除的文档,这意味着,段中存储着“被删除”的文档,这使得段中含有”正常文档“的密度降低。多个段可以通过段合并(Segment Merge)操作把“已删除”的文档将从段中物理删除,把未删除的文档合并到一个新段中,新段中没有”已删除文档“,因此,段合并操作能够提高索引的查找速度,但段合并是IO密集型的操作,需要消耗大量的硬盘IO。

首先了解RESTful API的调用风格,在管理和使用ElasticSearch服务时,常用的HTTP动词有下面五个:

    GET 请求:获取服务器中的对象  相当于SQL的Select命令

         GET /blogs:列出所有博客

    POST 请求:在服务器上更新对象  相当于SQL的Update命令

        POST /blogs/ID:更新指定的博客

    PUT 请求:在服务器上创建对象 相当于SQL的Create命令

        PUT /blogs/ID:新建一个博客  

     DELETE 请求:删除服务器中的对象 相当于SQL的Delete命令

        DELETE /blogs/ID:删除指定的博客

    HEAD 请求:仅仅用于获取对象的基础信息

下面简单的对商品信息进行CRUD(增删改查)操作:

新增商品:新增文档,建立索引:

PUT /index/type/id
{
  "json数据"
}

image.png

java 客户端方式:

public static void main(String[] args) throws Exception {
// 先构建client
Settings settings = Settings.builder()
.put("cluster.name", "elasticsearch")
.build();
TransportClient client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
IndexResponse response = client.prepareIndex("company",  "employee","2")
.setSource(XContentFactory.jsonBuilder().startObject().field("name", "jack")
.field("age", 27)
.field("position", "technique")
.field("country", "china")
.field("join_date", "2017-01-01")
.field("salary", 10000).endObject()
).execute().actionGet();
System.out.println(response.getId());
client.close();
}

另外一种,是把数据构造成json串,直接传给client 

image.png

(2)查询商品:检索文档

  GET /company/employee/2

    image.png

java 客户端方式:

GetResponse getResponse = client.prepareGet("company", "employee", "1").get();
System.out.println(getResponse.getSourceAsString());

(3)修改商品:替换文档

PUT /megacorp/employee/4
{
    "first_name" : "John",
    "last_name" :  "Smith",
    "age" :        25,
    "about" :      "I love to go rock climbing",
    "interests": [ "sports", "music" ]
}

    image.png

返回信息:

result=created  created=true 说明是创建数据

version=1  版本号为1

  image.png

返回信息:

result=updated created=false 说明是修改数据

version=2  版本号为2

所以elstaticsearch执行put时是这样的:

   如果指定id不存在就新增一条数据,存在时就覆盖

   实际上创建document时ID是可选参数。如果未指定,Elasticsearch将生成一个随机ID。

   不指定id创建时document需要使用POST命令

 image.png

返回信息:

这里的id=AVpQdsOSxaunvQAUZY5w就是Elasticsearch随机生成的

上述的PUT方式不好之处就是: 实际上Elasticsearch不会在内部进行更新。每当我们进行更新时,Elasticsearch将删除旧document,然后再创建一个新的。所以利用PUT方式的更新必须是带上所有的信息才能更新

利用POST方式更新商品文档信息:

POST /megacorp/employee/AWCda7ThZwfid3Y2p3xV/_update
{
    "doc": {
      "first_name" : "John Smith"
    }
    
}

局部更新某个字段;

 image.png

Java客户端执行方式:

 image.png

(4)删除商品:删除文档

 image.png

Java客户端执行方式:

DeleteResponse deleteResponse= client.prepareDelete("company",  "employee","2").get();
System.out.println(deleteResponse.getResult());

中文教程:

  https://es.xiaoleilu.com/402_Nested/30_Nested_objects.html

发表评论