ElasticSearch——高性能分布式搜索引擎

Elasticsearch 简介

Elasticsearch(简称 es)是一款高性能的实时分布式搜索和分析引擎,它可以从海量数据中快速的找到相关信息。作为一款功能强大的分布式搜索引擎,支持近实时的存储、搜索数据。被许多公司广泛的应用

  • github 使用 ElasticSearch 检索 1300 亿行代码
  • 维基百科使用 Elasticsearch 提供全文搜索并高亮关键字,以及输入实时搜索和搜索纠错等搜索建议功能
  • StackOverflow 结合全文搜索与地理位置查询,以及 more-like-this 功能来找到相关的问题和答案

概念

Elasticsearch 有几个核心概念,这里先讲解几个概念,对下面的学习过程比较有帮助

  • 接近实时
    Elasticsearch 是一个近实时的搜索引擎,从插入一条数据到数据能被检索到大概有一个 1s 的轻微延迟。所以 Elasticsearch 不适合用于对实时性要求很高的业务

  • 分布式
    对于大多数数据库而言,如果想很想扩展,需要对你的程序做相应的改动,大部分时候改动还不小。而Elasticsearch 天生就是分布式的,这意味着它能自动管理节点来提供高扩展和高可用,你不必关心这些,只需要部署多一台服务器即可

  • 索引(index)
    一个索引就是一个拥有相似特征的文档的集合,比如在一个订单系统中,可以有客户数据的索引、产品数据的索引、订单数据的索引,当需要检索特定数据的时候,只需要操作对应的索引即可

  • 文档
    Elasticsearch 跟 mysql 这种关系型数据库不同, Elasticsearch 不会将信息存储为列数据的行,而是将数据序列化成 JSON 文档的结构进行存储。比如在客户索引中,一条客户数据就可以称之为一个文档

  • 字段类型
    Elasticsearch 支持以下简单字段类型

类型表示的数据类型
Stringstring
Whole numberbyte,short,integer,long
Floating pointfloat,double
Booleanboolean
Datedate
  • 映射
    Elasticsearch 在存储数据的时候,不需要事先声明数据的字段及类型,Elasticsearch 会使用默认的动态映射猜测字段的类型进行存储

安装

Elasticsearch 安装很简单,我们只需要到 Elasticsearch 官网 下载最新版的 ElasticSearch 压缩包(目前最新版是 7.6.0),然后解压运行 bin/elasticsearch.sh 脚本就行啦(Windows 运行bin\elasticsearch.bat)

ElasticSearch 默认启动端口是 9200,测试 ElasticSearch 是否启动成功,访问 http://localhost:9200,如果浏览器返回以下信息证明启动成功

{
  "name" : "es01",
  "cluster_name" : "es-cluster-name",
  "cluster_uuid" : "rfEcJdBuQYi951oNAA76cw",
  "version" : {
    "number" : "7.6.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "7f634e9f44834fbc12724506cc1da681b0c3b1e3",
    "build_date" : "2020-02-06T00:09:00.449973Z",
    "build_snapshot" : false,
    "lucene_version" : "8.4.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

基础操作

任何程序都能使用 RESTful API,通过 9200 端口与 Elasticsearch 进行通信。向 Elasticsearch 发出的请求的组成部分与其他普通的 HTTP 请求是一样的,举例说明,想要计算集群中的文档数量,我们可以这样做:

curl -XGET 'http://localhost:9200/_count?pretty' -H 'Content-Type: application/json' -d '
{
	"query": {
		"match_all": {}
	}
}
'

Elasticsearch 返回一个类似 200 OK 的 HTTP 状态码和 JSON 格式的响应主题(除了 HEAD 请求)。上面的请求会得到如下的 JSON 格式的相应主体:

{
  "count" : 0,
  "_shards" : {
    "total" : 0,
    "successful" : 0,
    "skipped" : 0,
    "failed" : 0
  }
}

为简单起见,下面统一将请求简写成这样

GET /_count
{
	"query": {
		"match_all": {}
	}
}

下面演示如何通过 Elasticsearch 进行数据的存储与检索,假设我们要存储一些员工数据,先创建员工索引

POST /employee
{
  "mappings": {
    "properties": {
      "first_name": {
        "type": "keyword"
      },
      "last_name": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      },
      "about": {
		"type": "text"
	  },
      "interests": {
        "type": "keyword"
      }
    }
  }
}
  • 插入一条员工数据
POST /employee/_doc/1
{
  "first_name": "John",
  "last_name": "Smith",
  "age": 25,
  "about" : "I love to go rock climbing",
  "interests": [ "sports", "music" ]
}

可以看到 path:/employee/_doc/1 包含三部分信息

名字说明
employee索引名称
_doc文档类型,es 7 之后取消自定义文档类型,这里可以简单理解为一个关键字
1这个员工的ID

很简单吧,接下来准备多2条员工数据

POST /employee/_doc/2
{
  "first_name": "Jane",
  "last_name": "Smith",
  "age": 32,
  "about": "I like to colelct rock albums",
  "interests": [ "music" ]
}

POST /employee/_doc/3
{
  "first_name": "Douglas",
  "last_name": "Fir",
  "age": 35,
  "about": "I like to buid cabinets",
  "interests": [ "forestry" ]
}

  • 根据 id 查询员工信息
    这对于Elasticsearch来说非常简单。我们只要执行HTTP GET请求并指出文档的“地址”——索 引、类型和ID既可。根据这三部分信息,我们就可以返回原始JSON文档,比如获取第一个员工的信息
GET /employee/_doc/1

响应的内容中包含一些文档的元信息,John Smith的原始JSON文档包含在 _source 字段中

{
	"_index": "employee",
	"_type": "_doc",
	"_id": "1",
	"_version": 1,
	"_seq_no": 0,
	"_primary_term": 1,
	"found": true,
	"_source":{
		"first_name": "John",
		"last_name": "Smith",
		"age": 25,
		"about": "I like to buid cabinets",
		"interests":[
			"sports",
			"music"
		]
	}
}

更复杂的搜索

上面是直接根据 id 搜索,下面让搜索稍微再变的复杂一些。我们依旧想要找到姓氏为“Smith”的员工,但是我们只想得到年龄大于30岁的员工。复杂搜索中的请求关键字是_search,我们的语句将添加过滤器(filter),它使得我们高效率的执行一个结构化搜索:

GET /megacorp/employee/_search 
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "age": {
              "gt": 30 <1>
            }
          }
        },
        {
          "match": {
            "last_name": "Smith" <2>
          }
        }
      ]
    }
  }
}

<1> 这部分查询属于“区间过滤器”(range filter),它用于查询所有年龄大于 30 岁的数据
<2> 这部分查询用于查询 last_name 为 smith 的数据
整条查询语句的意思就是查询出“在employee索引哩查处年龄大于30岁,姓氏为smith的员工“

Elasticsearch 返回结果为

{
  "took" : 41,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.4700036,
    "hits" : [
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.4700036,
        "_source" : {
          "first_name" : "Jane",
          "last_name" : "Smith",
          "age" : 32,
          "about" : "I like to colelct rock albums",
          "interests" : [
            "music"
          ]
        }
      }
    ]
  }
}

如果说上面的功能都很简单的话,那么接下来的搜索就是传统数据库很难实现的功能。如搜索喜欢“rock climbing"的员工:

GET /employee/_search
{
	"query": {
		"match": {
			"about": "rock climbing"
		}
	}
}

该查询会得到两个匹配文档:

{
  "took" : 690,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.4167401,
    "hits" : [
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.4167401,
        "_source" : {
          "first_name" : "John",
          "last_name" : "Smith",
          "age" : 25,
          "about" : "I love to go rock climbing",
          "interests" : [
            "sports",
            "music"
          ]
        }
      },
      {
        "_index" : "employee",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.4589591,
        "_source" : {
          "first_name" : "Jane",
          "last_name" : "Smith",
          "age" : 32,
          "about" : "I like to colelct rock albums",
          "interests" : [
            "music"
          ]
        }
      }
    ]
  }
}

可以看到返回的两条文档都有一个 _score 字段,该字段为结果相关性评分,所谓结果相关性评分就是文档与查询条件的匹配程度,得分越高表示匹配相关性越高

我们搜索的是 about 字段有 ”rock climbing“ 关键字的文档,但是 Jane Smith 为什么也会出现在结果中呢?这是因为 Jane Smith 的 about 字段中也有 “rock” 关键字,所以它他也会被检索到,但是结果相关性评分比较低

这个例子很好的解释了 Elasticsearch 是如何在各种文本字段中进行全文搜索,并返回相关性结果结合的。相关性(relevance)的概念在Elasticsearch中非常重要,而这个概念在传统关 系型数据库中是不可想象的,因为传统数据库对记录的查询只有匹配或者不匹配

公众号

觉得不错可以关注我的公众号
簧笑语

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值