当你发现自己的才华撑不起野心时,就请安静下来学习吧。

Personal site

↑点击传送

ElasticSearch

介绍

Elasticsearch是什么

elasticsearch是一个基于Lucene的分布式搜索和引擎

elasticsearch是一个开源的高扩展的分布式全文搜索引擎,它可以近乎实时的储存、检索数据;本身扩展性很好,可以扩展到上摆台服务器,处理PB级别的数据

Java开发,遵循Apache开源协议

使用Lucene作为其核心来实现所有的索引和搜索功能,但是它的目的是通过简单的RESTFUL API来隐藏Lucene的复杂性,使得全文检索变得简单

Lucene与Elasticearch关系

1 Lucne只是一个库,想要使用它,你必须使用java来作为开发语言并将其直接集尘到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入连接检索的相关知识来理解它是如何工作的

2 Elasticsearch也使用java开发并使用Lucene作为其核心来实现所有的索引和搜索的功能,但是他的目的是通过简单的RESTFUL API来隐藏Lucene的复杂性,从而让全文搜索变得简单

Elasticsearch vs solr

1)Solr是Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。

2)Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持。

3)Solr是用Java编写、运行在Servlet容器(如 Apache Tomcat 或Jetty)的一个独立的全文搜索服务器。 Solr采用了 Lucene Java 搜索库为核心的全文索引和搜索,并具有类似REST的HTTP/XML和JSON的API。

4)Solr强大的外部配置功能使得无需进行Java编码,便可对 其进行调整以适应多种类型的应用程序。Solr有一个插件架构,以支持更多的高级定制

Elasticsearch 与 Solr 的比较总结

1. 二者安装都很简单
2. Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能
3. Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式
4. Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供
5. Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch
6. Solr 是传统搜索应用的有力解决方案,但 Elasticsearch 更适用于新兴的实时搜索应用

Elasticsearch核心概念

Cluster:集群

ES可以作为一个独立的单个搜索服务器。不过,为了处理大型数据集,实现容错和高可用性,ES可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。

Node:节点

形成集群的每个服务器称为节点

Shard:分片

当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。这种情况下,数据可以分为较小的分片。每个分片放到不同的服务器上。
当你查询的索引分布在多个分片上时,ES会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。即:这个过程对用户来说是透明的。

Replia:副本

为提高查询吞吐量或实现高可用性,可以使用分片副本。
副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。
当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片。

全文检索

全文检索就是对一篇文章进行索引,可以根据关键字搜索,类似于mysql里的like语句。
全文索引就是把内容根据词的意义进行分词,然后分别创建索引,例如”今日是周日我们出去玩” 可能会被分词成:“今天“,”周日“,“我们“,”出去玩“ 等token,这样当你搜索“周日” 或者 “出去玩” 都会把这句搜出来。

与关系型数据库MySql对比

image-20191223153358211

1)关系型数据库中的数据库(DataBase),等价于ES中的索引(Index)
2)一个数据库下面有N张表(Table),等价于1个索引Index下面有N多类型(Type),
3)一个数据库表(Table)下的数据由多行(ROW)多列(column,属性)组成,等价于1个Type由多个文档(Document)和多Field组成。
4)在一个关系型数据库里面,schema定义了表、每个表的字段,还有表和字段之间的关系。 与之对应的,在ES中:Mapping定义索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。
5)在数据库中的增insert、删delete、改update、查search操作等价于ES中的增PUT/POST、删Delete、改_update、查GET.1.7

ES逻辑设计(文档-->类型-->索引)

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

文档

之前说elasticsearch是面向文档的,那么就意味着索引和搜索数据的最小单位是文档,elasticsearch中,文档有几个重要属性:

  • 自我包含,一篇文档同时包含字段和对应的值,也就是同时包含key:value
  • 可以是层次型的,一个文档中包含自文档,复杂的逻辑实体就是这么来的
  • 灵活的结构,文档不依赖预先定义的模式,我们知道关系型数据库中,要提前定义字段才能使用,在elasticsearch中,对于字段是非常灵活的,有时候,我们可以忽略该字段,或者动态的添加一个新的字段。
  • 文档是无模式的,也就是说,字段对应值的类型可以是不限类型的。

尽管我们可以随意的新增或者忽略某个字段,但是,每个字段的类型非常重要,比如一个年龄字段类型,可以是字符串也可以是整型。因为elasticsearch会保存字段和类型之间的映射及其他的设置。这种映射具体到每个映射的每种类型(详见扩展阅读:17-扩展阅读-删除映射类型.md),这也是为什么在elasticsearch中,类型有时候也称为映射类型。

类型

类型是文档的逻辑容器,就像关系型数据库一样,表格是行的容器。
类型中对于字段的定义称为映射,比如name映射为字符串类型。
我们说文档是无模式的,它们不需要拥有映射中所定义的所有字段,比如新增一个字段,那么elasticsearch是怎么做的呢?elasticsearch会自动的将新字段加入映射,但是这个字段的不确定它是什么类型,elasticsearch就开始猜,如果这个值是18,那么elasticsearch会认为它是整型。
但是elasticsearch也可能猜不对,所以最安全的方式就是提前定义好所需要的映射,这点跟关系型数据库殊途同归了,先定义好字段,然后再使用,别整什么幺蛾子。后面在讨论更多关于映射的东西。

索引

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

ES物理设计

一个集群包含至少一个节点,而一个节点就是一个elasticsearch进程。节点内可以有多个索引。
默认的,如果你创建一个索引,那么这个索引将会有5个分片(primary shard,又称主分片)构成,而每个分片又有一个副本(replica shard,又称复制分片),这样,就有了10个分片。
那么这个索引是如何存储在集群中的呢?
图中有3个节点的集群,可以看到主分片和对应的复制分片都不会在同一个节点内,这样有利于某个节点挂掉了,数据也不至于丢失。
实际上,一个分片是一个Lucene索引,一个包含倒排索引的文件目录,倒排索引的结构使得elasticsearch在不扫描全部文档的情况下,就能告诉你哪些文档包含特定的关键字

image-20200306181921343

ELK是什么

ELK=elasticsearch+Logstash+kibana
elasticsearch:后台分布式存储以及全文检索
logstash: 日志加工、“搬运工”
kibana:数据可视化展示。
ELK架构为数据分布式存储、可视化查询和日志解析创建了一个功能强大的管理链。 三者相互配合,取长补短,共同完成分布式大数据处理工作。

Elasticsearch特点和优势

1)分布式实时文件存储,可将每一个字段存入索引,使其可以被检索到。
2)实时分析的分布式搜索引擎。
分布式:索引分拆成多个分片,每个分片可有零个或多个副本。集群中的每个数据节点都可承载一个或多个分片,并且协调和处理各种操作;
负载再平衡和路由在大多数情况下自动完成。
3)可以扩展到上百台服务器,处理PB级别的结构化或非结构化数据。也可以运行在单台PC上(已测试)
4)支持插件机制,分词插件、同步插件、Hadoop插件、可视化插件等。

为什么使用Elasticsearch

国内外优秀案例

1) 2013年初,GitHub抛弃了Solr,采取ElasticSearch 来做PB级的搜索。 “GitHub使用ElasticSearch搜索20TB的数据,包括13亿文件和1300亿行代码”。

2)维基百科:启动以elasticsearch为基础的核心搜索架构。
3)SoundCloud:“SoundCloud使用ElasticSearch为1.8亿用户提供即时而精准的音乐搜索服务”。
4)百度:百度目前广泛使用ElasticSearch作为文本数据分析,采集百度所有服务器上的各类指标数据及用户自定义数据,通过对各种数据进行多维分析展示,辅助定位分析实例异常或业务层面异常。目前覆盖百度内部20多个业务线(包括casio、云分析、网盟、预测、文库、直达号、钱包、风控等),单集群最大100台机器,200个ES节点,每天导入30TB+数据。

5)新浪ES 如何分析处理32亿条实时日志
6)阿里ES 构建挖财自己的日志采集和分析体系
7)有赞ES 业务日志处理

我们的业务场景

实际项目开发实战中,几乎每个系统都会有一个搜索的功能,当搜索做到一定程度时,维护和扩展起来难度就会慢慢变大,所以很多公司都会把搜索单独独立出一个模块,用ElasticSearch等来实现。

近年ElasticSearch发展迅猛,已经超越了其最初的纯搜索引擎的角色,现在已经增加了数据聚合分析(aggregation)和可视化的特性,如果你有数百万的文档需要通过关键词进行定位时,ElasticSearch肯定是最佳选择。当然,如果你的文档是JSON的,你也可以把ElasticSearch当作一种“NoSQL数据库”, 应用ElasticSearch数据聚合分析(aggregation)的特性,针对数据进行多维度的分析。

尝试使用ES来替代传统的NoSQL,它的横向扩展机制太方便了

应用场景:

1)新系统开发尝试使用ES作为存储和检索服务器;
2)现有系统升级需要支持全文检索服务,需要使用ES

Elasticsearch索引到底能处理多大数据

单一索引的极限取决于存储索引的硬件、索引的设计、如何处理数据以及你为索引备份了多少副本。

通常来说,一个Lucene索引(也就是一个elasticsearch分片,一个es索引默认5个分片)不能处理多于21亿篇文档,或者多于2740亿的唯一词条。但达到这个极限之前,我们可能就没有足够的磁盘空间了!
当然,一个分片如何很大的话,读写性能将会变得非常差

ElasticSearch安装

安装JDK环境

因为ElasticSearch使用Java语言编写的,所以必须安装JDK的环境,并且是JDK1.8以上,具体步骤百度

查看Java版本

java -version

官网下载最新版本

下载地址[https://www.elastic.co/cn/downloads/elasticsearch]

image-20191204173716931

下载其他版本

直接点击https://www.elastic.co/cn/downloads/past-releases#elasticsearch

image-20191204173847321

下载完成,启动

解压文件,切换到解压文件路径下,执行

cd elasticsearch-<version> #切换到路径下

./bin/elasticsearch  #启动es

#如果你想把 Elasticsearch 作为一个守护进程在后台运行,那么可以在后面添加参数 -d 。

#如果你是在 Windows 上面运行 Elasticseach,你应该运行 bin\elasticsearch.bat 而不是 bin\elasticsearch

测试启动是否成功

在浏览器输入以下地址:http://127.0.0.1:9200/

即可看到如下内容:

{
  "name" : "lqzMacBook.local",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "G1DFg-u6QdGFvz8Z-XMZqQ",
  "version" : {
    "number" : "7.5.0",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "e9ccaed468e2fac2275a3761849cbee64b39519f",
    "build_date" : "2019-11-26T01:06:52.518245Z",
    "build_snapshot" : false,
    "lucene_version" : "8.3.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

image-20201024201023571

关闭ES

#查看进程
ps -ef | grep elastic

#干掉进程
kill -9 2382(进程号)

#以守护进程方式启动es
elasticsearch -d

ElascticSearch插件介绍

es插件是一种增强Elasticsearch核心功能的途径。它们可以为es添加自定义映射类型、自定义分词器、原生脚本、自伸缩等等扩展功能。

es插件包含JAR文件,也可能包含脚本和配置文件,并且必须在集群中的每个节点上安装。安装之后,需要重启集群中的每个节点才能使插件生效。
es插件包含核心插件和第三方插件两种

核心插件

核心插件是elasticsearch项目提供的官方插件,都是开源项目。这些插件会跟着elasticsearch版本升级进行升级,总能匹配到对应版本的elasticsearch,这些插件是有官方团队和社区成员共同开发的。

官方插件地址: https://github.com/elastic/elasticsearch/tree/master/plugins

第三方插件

​ 第三方插件是有开发者或者第三方组织自主开发便于扩展elasticsearch功能,它们拥有自己的许可协议,在使用它们之前需要清除插件的使用协议,不一定随着elasticsearch版本升级, 所以使用者自行辨别插件和es的兼容性。

插件安装

elasticsearch的插件安装方式还是很方便易用的。

它包含了命令行和离线安装几种方式。

它包含了命令行,url,离线安装三种方式。

核心插件随便选择一种方式安装均可,第三方插件建议使用离线安装方式
第一种:命令行

bin/elasticsearch-plugin install [plugin_name]
# bin/elasticsearch-plugin install analysis-smartcn  安装中文分词器

第二种:url安装

bin/elasticsearch-plugin install [url]
#bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip

第三种:离线安装

#https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip
#点击下载analysis-smartcn离线包
#将离线包解压到ElasticSearch 安装目录下的 plugins 目录下
#重启es。新装插件必须要重启es

注意:插件的版本要与 ElasticSearch 版本要一致

Kibana安装(postman)

1 客户端:浏览器,postman,kibana,elasticsearch-head(没有桌面版客户端)

2 官方提供的
	-Kibana 是一款开源的数据分析和可视化平台
    -Kibana一定要跟es版本对应,咱们用的都是7.5.0

3 解压,就可以运行

4 连接es,需要配置
	-修改kibana配置
    # kibana监听的端口和地址
    server.port: 5601
    server.host: "127.0.0.1"
    server.name: lqz
    # 连接哪个es
    elasticsearch.hosts: ["http://localhost:9200/"]

elasticsearch-head安装

1 第三方开发的一个es客户端(nodjs开发的,装node环境)

2 下载,解压

3 cd elasticsearch-head目录下, npm install  安装依赖

4 npm run serve 跑起来

5 会出现跨域,es目录下config下elasticsearch.yml添加es配置
    http.cors.enabled: true
    http.cors.allow-origin: "*"

6 浏览器输入
	http://localhost:9100/

es安装官方,第三方插件

# 三种安装方式
# 推荐用第三种
 **第一种:命令行**
bin/elasticsearch-plugin install [plugin_name]
# bin/elasticsearch-plugin install analysis-smartcn  安装中文分词器

**第二种:url安装**

bin/elasticsearch-plugin install [url]
#bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip

**第三种:离线安装**
#https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-smartcn/analysis-smartcn-6.4.0.zip
#点击下载analysis-smartcn离线包
#将离线包解压到ElasticSearch 安装目录下的 plugins 目录下
#重启es。新装插件必须要重启es
​```

**注意:插件的版本要与 ElasticSearch 版本要一致**

倒排索引

1 倒排索引:对文章进行分词,对每个词建立索引,由于这样建,会出现索引爆炸,索引跟标题建关系,标题再跟文章建索引,如下:
	分词---文章建立索引                             |

| 今天(索引)    | (文章1,<2,10>,2) (文章3,<8>,1)       |
| 星期天(索引) | (文章2,<12,25,100>,3)                 |
| 出去玩(索引) | (文章5,<11,24,89>,3)(文章1,<8,19>,2) |

今天出现在哪个文章,出现的位置和出现的次数

索引操作(数据库)

1 新建索引
PUT lqz2
{
  "settings": {
    "index":{
      "number_of_shards":5,
      "number_of_replicas":1
    }
  }
}

# 新建索引
PUT lqz2
{
  "settings": {
    "index":{
      "number_of_shards":5,
      "number_of_replicas":1
    }
  }
}
PUT lqz


# 查看索引
GET lqz2/_settings
GET lqz/_settings
GET _all/_settings

GET lqz,lqz2/_settings
GET _settings


# 修改索引(一般不太用,只能用来修改副本数量)
#修改索引副本数量为2  分片的数量一开始就要定好
# 副本数量可以改(有可能会出错)
PUT lqz/_settings
{
  "number_of_replicas": 2
}

PUT  _all/_settings
{
"index": {
  "blocks": {
    "read_only_allow_delete": false
    }
  }
}



# 删除索引
DELETE lqz


映射管理(类型)(表)

#1  在Elasticsearch 6.0.0或更高版本中创建的索引只包含一个mapping type。 在5.x中使用multiple mapping types创建的索引将继续像以前一样在Elasticsearch 6.x中运行。 Mapping types将在Elasticsearch 7.0.0中完全删除



##索引如果不创建,只有插入文档,会自动创建

# 创建映射(类型,表)
PUT books
{
  "mappings": {
    "properties":{
      "title":{
        "type":"text",
        "analyzer": "ik_max_word"
      },
      "price":{
        "type":"integer"
      },
      "addr":{
        "type":"keyword"
      },
      "company":{
        "properties":{
          "name":{"type":"text"},
          "company_addr":{"type":"text"},
          "employee_count":{"type":"integer"}
        }
      },
      "publish_date":{"type":"date","format":"yyy-MM-dd"}
      
    }
    
  }
}



###查看映射
GET lqz/_mapping
GET _all/_mapping


# 特殊说明索引映射都不存在,也可以插入文档
PUT lqz1/_doc/1
{
  "title":"白雪公主和十个小矮人",
  "price":"99",
  "addr":"黑暗森里",
  "publish_date":"2018-05-19",
  "name":"lqz"
}
# 查看索引
GET lqz/_settings
#查看映射
GET lqz/_mapping

文档基本增删查改(一行一行数据)

# 1 插入文档
PUT books/_doc/1
{
  "title":"大头儿子小偷爸爸",
  "price":100,  
  "addr":"北京天安门",
  "company":{
    "name":"我爱北京天安门",
    "company_addr":"我的家在东北松花江傻姑娘",
    "employee_count":10
  },
  "publish_date":"2019-08-19"
}

PUT books/_doc/2
{
  "title":"白雪公主和十个小矮人",
  "price":"99", #写字符串会自动转换
  "addr":"黑暗森里",
  "publish_date":"2018-05-19"
}

PUT books/_doc/3
{
  "title":"白雪公主和十个小矮人",
  "price":"99", #写字符串会自动转换
  "addr":"黑暗森里",
  "publish_date":"2018-05-19",
   "name":"lqz"
}



## 查询文档
GET lqz/_doc/1

## 修改文档两种方式
# 第一种
PUT lqz/_doc/1
{
  "name":"顾老二",
  "age":30,
  "from": "gu",
  "desc": "皮肤黑、武器长、性格直",
  "tags": ["黑", "长", "直"]
}
# 第二种(局部修改)
POST lqz/_doc/1/_update
{
  "doc": {
    "desc": "皮肤很safasdfsda黄,武器很长,性格很直",
    "tags": ["很黄","很长", "很直"]
  }
}



## 删除文档
DELETE lqz/_doc/4

文档查询

###查询字符串
# 查询from字段是gu的所有人
GET lqz/_doc/_search?q=from:gu
# 查询age是22的人
GET lqz/_doc/_search?q=age:22

GET lqz/_doc/_search?q=desc:不知道
    
    
    
###结构化查询

GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  }
}

GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from":"gu"
    }
  }
}

模糊查询

match_all:查询所有
match_phrase:短语查询

GET t1/doc/_search
{
  "query": {
    "match_phrase": {
      "title": {
        "query": "中国世界",
        "slop": 2  # 中国和世界之间最多间隔2个字符
      }
    }
  }
}

文档查询操作

match和term查询

# 并且和或者的条件
#并且
GET t3/doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "beautiful"
          }
        },
        {
          "match": {
            "desc": "beautiful"
          }
        }
      ]
    }
  }
}

#或者
GET t3/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title": "beautiful"
          }
        },
        {
          "match": {
            "desc": "beautiful"
          }
        }
      ]
    }
  }
}



# match,term和terms的区别
	-match查的短语会分词
    GET w10/_doc/_search
        {
          "query": {
            "match": {
              "t1": "Beautiful girl!"
            }
          }
        }
    -term查的不会分词
    GET w10/_doc/_search
            {
          "query": {
            "term": {
              "t1": "girl"
            }
          }
        }
    -terms由于部分词,想查多个,terms
        GET w10/_doc/_search
        {
          "query": {
            "terms": {
              "t1": ["beautiful", "sexy"]
            }
          }
        }
        
        
        
# pymysql   原生操作,查出字典
# orm       orm直接转成对象

排序查询

##### 不是所有字段都支持排序,只有数字类型,字符串不支持

GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  }
}

#降序
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

## 升序
GET lqz/_doc/_search
{
  "query": {
    "match": {
      "from": "gu"
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}


GET lqz/_doc/_search
{
  "query": {
    "match_all": {
    }
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

分页查询

#从第二条开始,取一条
GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ], 
  "from": 2,
  "size": 2
}




###注意:对于`elasticsearch`来说,所有的条件都是可插拔的,彼此之间用`,`分割
GET lqz/_doc/_search
{
  "query": {
    "match_all": {}
  }, 
  "from": 2,
  "size": 2
}

布尔查询

- must(and)
- should(or)
- must_not(not)

##布尔查询之must and条件
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "name": "顾老二"
          }
        }
      ]
    }
  }
}


##布尔查询之should or条件
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "name": "龙套偏房"
          }
        }
      ]
    }
  }
}





### must_not条件   都不是
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "from": "gu"
          }
        },
        {
          "match": {
            "tags": "可爱"
          }
        },
        {
          "match": {
            "age": 18
          }
        }
      ]
    }
  }
}




###filter,大于小于的条件   gt lt  gte  lte
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "lt": 30
          }
        }
      }
    }
  }
}


### 范围查询
GET lqz/_doc/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "from": "gu"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gte": 25,
            "lte": 30
          }
        }
      }
    }
  }
}


### filter需要在bool内部,并且如果是and条件,需要用must,如果使用了should,会认为是should和filter是或者的关系
  • must:与关系,相当于关系型数据库中的and

  • should:或关系,相当于关系型数据库中的or

  • must_not:非关系,相当于关系型数据库中的not

  • filter:过滤条件。

  • range:条件筛选范围。

  • gt:大于,相当于关系型数据库中的>

  • gte:大于等于,相当于关系型数据库中的>=

  • lt:小于,相当于关系型数据库中的<

  • lte:小于等于,相当于关系型数据库中的<=

    查询结果过滤

    ###基本使用
    GET lqz/_doc/_search
    {
      "query": {
        "match_all": {
          }
      },
      "_source":["name","age"]
    }
    
    
    ####_source和query是平级的
    
    GET lqz/_doc/_search
    {
      "query": {
        "bool": {
          "must":{
            "match":{"from":"gu"}
          },
          
          "filter": {
            "range": {
              "age": {
                "lte": 25
              }
            }
          }
        }
      },
      "_source":["name","age"]
    }
    

    高亮查询

    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "highlight": {
        "pre_tags": "<b class='key' style='color:red'>",
        "post_tags": "</b>",
        "fields": {
          "from": {}
        }
      }
    }
    

    聚合查询

    # sum ,avg, max ,min
    
    # select max(age) as my_avg from 表 where from=gu;
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_avg": {
          "avg": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    #最大年龄
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_max": {
          "max": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    #最小年龄
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_min": {
          "min": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    # 总年龄
    #最小年龄
    GET lqz/_doc/_search
    {
      "query": {
        "match": {
          "from": "gu"
        }
      },
      "aggs": {
        "my_sum": {
          "sum": {
            "field": "age"
          }
        }
      },
      "_source": ["name", "age"]
    }
    
    
    
    #分组
    
    
    # 现在我想要查询所有人的年龄段,并且按照`15~20,20~25,25~30`分组,并且算出每组的平均年龄。
    GET lqz/_doc/_search
    {
      "size": 0, 
      "query": {
        "match_all": {}
      },
      "aggs": {
        "age_group": {
          "range": {
            "field": "age",
            "ranges": [
              {
                "from": 15,
                "to": 20
              },
              {
                "from": 20,
                "to": 25
              },
              {
                "from": 25,
                "to": 30
              }
            ]
          }
        }
      }
    }
    

    ik分词器使用

    #1 github下载相应版本
    https://github.com/medcl/elasticsearch-analysis-ik/releases?after=v7.5.2
    # 2 解压到es的plugin目录下
    # 3 重启es
    
    
    
    # ik_max_word 和 ik_smart 什么区别?
    
    ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;
    
    ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询。
    
    
    PUT books
    {
      "mappings": {
        "properties":{
          "title":{
            "type":"text",
            "analyzer": "ik_max_word"
          },
          "price":{
            "type":"integer"
          },
          "addr":{
            "type":"keyword"
          },
          "company":{
            "properties":{
              "name":{"type":"text"},
              "company_addr":{"type":"text"},
              "employee_count":{"type":"integer"}
            }
          },
          "publish_date":{"type":"date","format":"yyy-MM-dd"}
          
        }
        
      }
    }
    
    PUT books/_doc/1
    {
      "title":"大头儿子小偷爸爸",
      "price":100,  
      "addr":"北京天安门",
      "company":{
        "name":"我爱北京天安门",
        "company_addr":"我的家在东北松花江傻姑娘",
        "employee_count":10
      },
      "publish_date":"2019-08-19"
    }
    
    
    
    PUT books/_doc/2
    {
      "title":"白雪公主和十个小矮人",
      "price":"99",
      "addr":"黑暗森里",
      "company":{
        "name":"我的家乡在上海",
        "company_addr":"朋友一生一起走",
        "employee_count":10
      },
      "publish_date":"2018-05-19"
    }
    
    GET books/_mapping
    
    
    
    GET _analyze
    {
      "analyzer": "ik_max_word",
      "text": "白雪公主和十个小矮人"
    }
    GET books/_search
    {
      "query": {
        "match": {
          "title": "十"
        }
      }
    }
    
    
    
    PUT books2
    {
      "mappings": {
        "properties":{
          "title":{
            "type":"text",
            "analyzer": "ik_smart"
          },
          "price":{
            "type":"integer"
          },
          "addr":{
            "type":"keyword"
          },
          "company":{
            "properties":{
              "name":{"type":"text"},
              "company_addr":{"type":"text"},
              "employee_count":{"type":"integer"}
            }
          },
          "publish_date":{"type":"date","format":"yyy-MM-dd"}
          
        }
        
      }
    }
    
    
    PUT books2/_doc/1
    {
      "title":"大头儿子小偷爸爸",
      "price":100,  
      "addr":"北京天安门",
      "company":{
        "name":"我爱北京天安门",
        "company_addr":"我的家在东北松花江傻姑娘",
        "employee_count":10
      },
      "publish_date":"2019-08-19"
    }
    
    
    
    PUT books2/_doc/2
    {
      "title":"白雪公主和十个小矮人",
      "price":"99",
      "addr":"黑暗森里",
      "company":{
        "name":"我的家乡在上海",
        "company_addr":"朋友一生一起走",
        "employee_count":10
      },
      "publish_date":"2018-05-19"
    }
    
    
    GET _analyze
    {
      "analyzer": "ik_smart",
      "text": "白雪公主和十个小矮人"
    }
    GET books2/_search
    {
      "query": {
        "match": {
          "title": "十个"
        }
      }
    }
    

    Python中集成ES两种方式

    原生集成

    # Official low-level client for Elasticsearch
    
    ### 等同于pymysql
    #pip3 install elasticsearch
    
    
    from elasticsearch import Elasticsearch
    
    obj = Elasticsearch()   # 得到一个对象
    # 创建索引(Index)
    # result = obj.indices.create(index='user', body={"userid":'1','username':'lqz'},ignore=400)
    # print(result)
    # 删除索引
    # result = obj.indices.delete(index='user', ignore=[400, 404])
    # 插入数据
    # data = {'userid': '1', 'username': 'lqz','password':'123'}
    # result = obj.create(index='news', doc_type='_doc', id=1, body=data)
    # print(result)
    # 更新数据
    '''
    不用doc包裹会报错
    ActionRequestValidationException[Validation Failed: 1: script or doc is missing
    '''
    # data ={'doc':{'userid': '1', 'username': 'lqz','password':'123ee','test':'test'}}
    # result = obj.update(index='news', doc_type='_doc', body=data, id=1)
    # print(result)
    
    
    # 删除数据
    # result = obj.delete(index='news', doc_type='_doc', id=1)
    # print(result)
    
    # 查询
    # 查找所有文档
    # query = {'query': {'match_all': {}}}
    #  查找名字叫做jack的所有文档
    query = {'query': {'match': {'title': '十个'}}}
    
    # 查找年龄大于11的所有文档
    # query = {'query': {'range': {'age': {'gt': 11}}}}
    
    allDoc = obj.search(index='books', doc_type='_doc', body=query)
    # print(allDoc)
    print(allDoc['hits']['hits'][0]['_source'])
    

    dsl集成

    
    
    
    # Elasticsearch DSL is a high-level
    
    # pip3 install elasticsearch-dsl
    
    
    
    from datetime import datetime
    from elasticsearch_dsl import Document, Date, Nested, Boolean,analyzer, InnerDoc, Completion, Keyword, Text,Integer
    
    from elasticsearch_dsl.connections import connections
    
    connections.create_connection(hosts=["localhost"])
    
    
    class Article(Document):
        title = Text(analyzer='ik_max_word')
        author = Text()
    
        class Index:
            name = 'myindex'
    
        def save(self, ** kwargs):
            return super(Article, self).save(** kwargs)
    
    
    if __name__ == '__main__':
        # Article.init()  # 创建索引
        # 保存数据
        # article = Article()
        # article.title = "测试测试阿斯顿发送到发斯蒂芬啊啊士大夫阿斯蒂芬"
        # article.author = "lqz"
        # article.save()  # 数据就保存了
    
        #查询数据
        # s=Article.search()
        # s = s.filter('match', title="测试")
        #
        # results = s.execute()  # 执行
        # print(results[0].title)
    
        #删除数据
        s = Article.search()
        s = s.filter('match', title="李清照").delete()
    
        #修改数据
        # s = Article().search()
        # s = s.filter('match', title="测试")
        # results = s.execute()
        # print(results[0])
        # results[0].title="李清照阿斯顿发送到发送阿斯蒂"
        # results[0].save()
    

    集群搭建(脑裂)

    # 1 广播方式(一般不用)
    	-只要es节点能联通,ping,自动加人到节点中
        
    # 2 单播方式
    
    
    
    #1 elasticsearch1节点,,集群名称是my_es1,集群端口是9300;节点名称是node1,监听本地9200端口,可以有权限成为主节点和读写磁盘(不写就是默认的)。
    
    cluster.name: my_es1
    node.name: node1
    network.host: 127.0.0.1
    http.port: 9200
    transport.tcp.port: 9300
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    # 2 elasticsearch2节点,集群名称是my_es1,集群端口是9302;节点名称是node2,监听本地9202端口,可以有权限成为主节点和读写磁盘。
    
    cluster.name: my_es1
    node.name: node2
    network.host: 127.0.0.1
    http.port: 9202
    transport.tcp.port: 9302
    node.master: true
    node.data: true
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    # 3 elasticsearch3节点,集群名称是my_es1,集群端口是9303;节点名称是node3,监听本地9203端口,可以有权限成为主节点和读写磁盘。
    
    cluster.name: my_es1
    node.name: node3
    network.host: 127.0.0.1
    http.port: 9203
    transport.tcp.port: 9303
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    # 4 elasticsearch4节点,集群名称是my_es1,集群端口是9304;节点名称是node4,监听本地9204端口,仅能读写磁盘而不能被选举为主节点。
    
    cluster.name: my_es1
    node.name: node4
    network.host: 127.0.0.1
    http.port: 9204
    transport.tcp.port: 9304
    node.master: false
    node.data: true
    discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9302", "127.0.0.1:9303", "127.0.0.1:9304"]
    
    由上例的配置可以看到,各节点有一个共同的名字my_es1,但由于是本地环境,所以各节点的名字不能一致,我们分别启动它们,它们通过单播列表相互介绍,发现彼此,然后组成一个my_es1集群。谁是老大则是要看谁先启动了!
    
    
    
    #3 假设有7个节点
    	-由于网络问题  3个节点一组 , 4 个节点一组形成了两个机器
        -防止脑列
        	防止脑裂,我们对最小集群节点数该集群设置参数:(集群节点总数/2+1的个数)
    		discovery.zen.minimum_master_nodes: 3   # 3=5/2+1
    

    打分机制

    1 确定文档和查询有多么相关的过程被称为打分
    2 TF是词频(term frequency):一个词条在文档中出现的次数,出现的频率越高,表示相关度越高 3 IDF`是逆文档频率:如果一个词条在索引中的不同文档中出现的次数越多,那么它就越不重要

posted @ 2020-10-26 21:22  Joab-0429  阅读(176)  评论(1编辑  收藏  举报