大型的平台类网站建设需要多少资金,怎么样制作app的步骤,中国机械加工网18易8下4拉hu,营业执照年报入口1、全文检索
1.1、数据分类 按数据分类的话#xff0c;主要可以分为以下三类#xff1a;
结构化数据#xff1a;固定格式、有限长度#xff0c;比如mysql存的数据非结构化数据#xff1a;不定长、无固定格式#xff0c;比如邮件、Word文档、日志等半结构化数据#xf…1、全文检索
1.1、数据分类 按数据分类的话主要可以分为以下三类
结构化数据固定格式、有限长度比如mysql存的数据非结构化数据不定长、无固定格式比如邮件、Word文档、日志等半结构化数据前两者结合比如 xml、html等
1.2、搜索分类
结构化数据搜索使用关系型数据库非结构化数据搜索 顺序扫描全文检索 设想一个关于搜索的场景假设我们要搜索一首诗句内容中带“前”字的古诗
namecontentauthor静夜思床前明月光,疑是地上霜。举头望明月低头思故乡。李白望庐山瀑布日照香炉生紫烟遥看瀑布挂前川。飞流直下三千尺,疑是银河落九天。李白
思考用传统关系型数据库和ES 实现会有什么差别 如果用像 MySQL 这样的 RDBMS 来存储古诗的话我们应该会去使用这样的 SQL 去查询
select name from poems where content like %前% 这种我们称为顺序扫描法需要遍历所有的记录进行匹配。不但效率低而且不符合我们搜索时的期望比如我们在搜索“ABCD这样的关键词时通常还希望看到A,AB,CD,“ABC”的搜索结果。
1.3、什么是全文索引 全文检索是指通过一个程序扫描文本中的每一个单词针对单词建立索引并保存该单词在文本中的位置、以及出现的次数。用户查询时通过之前建立好的索引来查询将索引中单词对应的文本位置、出现的次数返回给用户因为有了具体文本的位置所以就可以将具体内容读取出来了。 搜索原理简单概括的话可以分为这么几步
内容爬取停顿词过滤比如一些无用的像的“了” 之类的语气词/连接词内容分词提取关键词根据关键词建立倒排索引用户输入关键词进行搜索
1.4、倒排索引 索引就类似于目录平时我们使用的都是索引都是通过主键定位到某条数据那么倒排索引呢刚好相反数据对应到主键。 1.4.1、正排索引正向索引
文章ID文章标题文章内容1浅析JAVA设计模式JAVA设计模式是每一个JAVA程序员都应该掌握的进阶知识2JAVA多线程设计模式JAVA多线程与设计模式结合
1.4.2、倒排索引反向索引 假如我们有一个站内搜索的功能通过某个关键词来搜索相关的文章那么这个关键词可能出现在标题中也可能出现在文章内容中那我们将会在创建或修改文章的时候建立一个关键词与文章的对应关系表这种我们可以称之为倒排索引。
关键词文章IDJAVA1,2设计模式1,2多线程2
2、Elasticsearch 简介
2.1、什么是 Elasticsearch ElasticSearch简称ES是一个分布式、RESTful 风格的搜索和数据分析引擎是用Java开发并且是当前最流行的开源的企业级搜索引擎能够达到近实时搜索稳定可靠快速安装使用方便。客户端支持Java、.NETC#、PHP、Python、Ruby等多种语言。
官方网站: Elasticsearch 平台 — 大规模查找实时答案 | Elastic
下载地址https://www.elastic.co/cn/downloads/past-releases#elasticsearch
当前搜索引擎最新排名参考网站 2.2、Elasticsearch 的版本特性 5.x 新特性 Lucene 6.x 性能提升默认打分机制从TF-IDF改为BM 25支持Ingest节点/ Painless Scripting / Completion suggested支持/原生的Java REST客户端Type标记成deprecated 支持了Keyword的类型性能优化 内部引擎移除了避免同一文档并发更新的竞争锁带来15% - 20%的性能提升Instant aggregation,支持分片上聚合的缓存新增了Profile API 6.x 新特性 Lucene 7.x新功能 跨集群复制(CCR)索引生命周期管理SQL的支持更友好的的升级及数据迁移 在主要版本之间的迁移更为简化体验升级全新的基于操作的数据复制框架可加快恢复数据性能优化 有效存储稀疏字段的新方法降低了存储成本在索引时进行排序可加快排序的查询性能 7.x 新特性 Lucene 8.0重大改进-正式废除单个索引下多Type的支持7.1开始Security 功能免费使用ECK - Elasticseach Operator on Kubernetes新功能 New Cluster coordinationFeature——Complete High Level REST ClientScript Score Query性能优化 默认的Primary Shard数从5改为1,避免Over Sharding性能优化 更快的Top K 8.x 新特性 Rest API相比较7.x而言做了比较大的改动比如彻底删除_type默认开启安全配置存储空间优化对倒排文件使用新的编码集对于keyword、match_only_text、text类型字段有效有3.5%的空间优化提升对于新建索引和segment自动生效。优化geo_pointgeo_shape类型的索引写入效率15%的提升。技术预览版KNN API发布K邻近算法跟推荐系统、自然语言排名相关。
2.3、Elasticsearch VS Solr Solr 是第一个基于 Lucene 核心库功能完备的搜索引擎产品诞生远早于 Elasticsearch。当单纯的对已有数据进行搜索时Solr更快。 当实时建立索引时, Solr会产生io阻塞查询性能较差, Elasticsearch具有明显的优势。 根据大型互联网公司实际生产环境测试将搜索引擎从Solr转到 Elasticsearch以后的平均查询速度有了50倍的提升。 总结
Solr 利用 Zookeeper 进行分布式管理而Elasticsearch 自身带有分布式协调管理功能。Solr 支持更多格式的数据比如JSON、XML、CSV而 Elasticsearch 仅支持json文件格式。Solr 在传统的搜索应用中表现好于 Elasticsearch但在处理实时搜索应用时效率明显低于 Elasticsearch。Solr 是传统搜索应用的有力解决方案但 Elasticsearch更适用于新兴的实时搜索应用。
2.4、Elastic Stack 介绍 在Elastic Stack之前我们听说过ELKELK分别是ElasticsearchLogstashKibana这三款软件在一起的简称在发展的过程中又有新的成员Beats的加入就形成了Elastic Stack。 在Elastic Stack生态圈中Elasticsearch作为数据存储和搜索是生态圈的基石Kibana在上层提供用户一个可视化及操作的界面Logstash和Beat可以对数据进行收集。在上图的右侧X-Pack部分则是Elastic公司提供的商业项目。 2.5、Elasticsearch 应用场景 国内现在有大量的公司都在使用 Elasticsearch包括携程、滴滴、今日头条、饿了么、360安全、小米、vivo等诸多知名公司。除了搜索之外结合Kibana、Logstash、BeatsElastic Stack还被广泛运用在大数据近实时分析领域包括日志分析、指标监控、信息安全等多个领域。它可以帮助你探索海量结构化、非结构化数据按需创建可视化报表对监控数据设置报警阈值甚至通过使用机器学习技术自动识别异常状况。
站内搜索日志管理与分析大数据分析应用性能监控机器学习 通用数据处理流程 3、Elasticsearch 快速开始
3.1、Elasticsearch 安装运行
1、环境准备
需安装并配置jdk各个版本对Java的依赖 https://www.elastic.co/support/matrix#matrix_jvm Elasticsearch 5需要Java 8以上的版本Elasticsearch 从6.5开始支持Java117.0开始内置了Java环境ES比较耗内存建议虚拟机4G或以上内存jvm1g以上的内存分配
可以参考es的环境文件elasticsearch-env.bat ES的jdk环境生效的优先级配置 ES_JAVA_HOME JAVA_HOME ES_HOME
2、下载并解压 Elasticsearch
下载地址 7.17.3 3、Elasticsearch 文件目录结构
目录描述bin脚本文件包括启动elasticsearch安装插件运行统计数据等config配置文件目录如elasticsearch配置、角色配置、jvm配置等。jdkjava运行环境data默认的数据存放目录包含节点、分片、索引、文档的所有数据生产环境需要修改。libelasticsearch依赖的Java类库logs默认的日志文件存储路径生产环境需要修改。modules包含所有的Elasticsearch模块如Cluster、Discovery、Indices等。plugins已安装插件目录 4、主配置文件(elasticsearch.yml)
配置项说明cluster.name当前节点所属集群名称多个节点如果要组成同一个集群那么集群名称一定要配置成相同。默认值elasticsearch生产环境建议根据ES集群的使用目的修改成合适的名字。node.name当前节点名称默认值当前节点部署所在机器的主机名所以如果一台机器上要起多个ES节点的话需要通过配置该属性明确指定不同的节点名称。path.data配置数据存储目录比如索引数据等默认值 $ES_HOME/data生产环境下强烈建议部署到另外的安全目录防止ES升级导致数据被误删除。path.logs配置日志存储目录比如运行日志和集群健康信息等默认值 $ES_HOME/logs生产环境下强烈建议部署到另外的安全目录防止ES升级导致数据被误删除。bootstrap.memory_lock配置ES启动时是否进行内存锁定检查默认值true。ES对于内存的需求比较大一般生产环境建议配置大内存如果内存不足容易导致内存交换到磁盘严重影响ES的性能。所以默认启动时进行相应大小内存的锁定如果无法锁定则会启动失败。非生产环境可能机器内存本身就很小能够供给ES使用的就更小如果该参数配置为true的话很可能导致无法锁定内存以致ES无法成功启动此时可以修改为false。network.host配置能够访问当前节点的主机默认值为当前节点所在机器的本机回环地址127.0.0.1 和[::1]这就导致默认情况下只能通过当前节点所在主机访问当前节点。可以配置为 0.0.0.0 表示所有主机均可访问。http.port配置当前ES节点对外提供服务的http端口默认值 9200discovery.seed_hosts配置参与集群节点发现过程的主机列表说白一点就是集群中所有节点所在的主机列表可以是具体的IP地址也可以是可解析的域名。cluster.initial_master_nodes配置ES集群初始化时参与master选举的节点名称列表必须与node.name配置的一致。ES集群首次构建完成后应该将集群中所有节点的配置文件中的cluster.initial_master_nodes配置项移除重启集群或者将新节点加入某个已存在的集群时切记不要设置该配置项。 JVM配置修改 修改 $ES_HOME/config/jvm.option 配置文件调整jvm堆内存大小
################################################################
## IMPORTANT: JVM heap size
################################################################
##
## The heap size is automatically configured by Elasticsearch
## based on the available memory in your system and the roles
## each node is configured to fulfill. If specifying heap is
## required, it should be done through a file in jvm.options.d,
## and the min and max should be set to the same value. For
## example, to set the heap to 4 GB, create a new file in the
## jvm.options.d directory containing these lines:
##
-Xms4g
-Xmx4g
配置的建议
Xms和Xms设置成—样Xmx不要超过机器内存的 50%不要超过30GB - A Heap of Trouble: Managing Elasticsearchs Managed Heap | Elastic Blog
5、启动服务 Windows 直接运行 elasticsearch.bat Linuxcentos7 ES不允许使用root账号启动服务如果你当前账号是root则需要创建一个专有账户
#非root用户
bin/elasticsearch
# -d 后台启动
bin/elasticsearch -d 注意es默认不能用root用户启动生产环境建议为elasticsearch创建用户。
#为elaticsearch创建用户并赋予相应权限
adduser es
passwd es
chown -R es:es .
elasticsearch-17.3
运行http://localhost:9200/ 如果ES服务启动异常会有提示 6、启动服务-常见错误
6.1、max file descriptors [4096]
max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536] ES因为需要大量的创建索引文件需要大量的打开系统的文件所以我们需要解除linux系统当中打开文件最大数目的限制不然ES启动就会抛错
\#切换到root用户
vim /etc/security/limits.conf
末尾添加如下配置
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
6.2、max number of threads [1024]
max number of threads [1024] for user [es] is too low, increase to at least [4096] 无法创建本地线程问题,用户最大可创建线程数太小
vim /etc/security/limits.d/20-nproc.conf
改为如下配置
* soft nproc 4096
6.3、max_map_count [65530]
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
最大虚拟内存太小,调大系统的虚拟内存
vim /etc/sysctl.conf
追加以下内容
vm.max_map_count262144
保存退出之后执行如下命令
sysctl -p
6.4、the default discovery settings
the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be
configured 缺少默认配置至少需要配置discovery.seed_hosts / discovery.seed_providers / cluster.initial_master_nodes中的一个参数。
discovery.seed_hosts集群主机列表discovery.seed_providers基于配置文件配置集群主机列表cluster.initial_master_nodes启动时初始化的参与选主的node生产环境必填
vim config/elasticsearch.yml
#添加配置
discovery.seed_hosts: [127.0.0.1]
cluster.initial_master_nodes: [node-1]
3.2、客户端 kibana 安装
1、下载并解压缩
下载地址Kibana 7.17.3 | Elastic 2、修改 kibana.yml
vim config/kibana.yml
server.port: 5601
#服务器ip
server.host: localhost
#elasticsearch的访问地址
elasticsearch.hosts: [http://localhost:9200]
#Kibana汉化
i18n.locale: zh-CN
3、运行 kibana
bin/kibana #后台启动
nohup bin/kibana
访问Kibana: http://localhost:5601/ 4、cat API
API用途/_cat/allocation查看单节点的shard分配整体情况/_cat/shards#查看各shard的详细情况/_cat/shards/{index}#查看指定分片的详细情况/_cat/master#查看master节点信息/_cat/nodes#查看所有节点信息/_cat/indices#查看集群中所有index的详细信息/_cat/indices/{index}#查看集群中指定index的详细信息/_cat/segments#查看各index的segment详细信息,包括segment名, 所属shard, 内存(磁盘)占用大小, 是否刷盘/_cat/segments/{index}#查看指定index的segment详细信息/_cat/count#查看当前集群的doc数量/_cat/count/{index}#查看指定索引的doc数量/_cat/recovery#查看集群内每个shard的recovery过程.调整replica。/_cat/recovery/{index}#查看指定索引shard的recovery过程/_cat/health#查看集群当前状态红、黄、绿/_cat/pending_tasks#查看当前集群的pending task/_cat/aliases#查看集群中所有alias信息,路由配置等/_cat/aliases/{alias}#查看指定索引的alias信息/_cat/thread_pool#查看集群各节点内部不同类型的threadpool的统计信息/_cat/plugins#查看集群各个节点上的plugin信息/_cat/fielddata#查看当前集群各个节点的fielddata内存使用情况/_cat/fielddata/{fields}#查看指定field的内存使用情况,里面传field属性对应的值/_cat/nodeattrs#查看单节点的自定义属性/_cat/repositories#输出集群中注册快照存储库/_cat/templates#输出当前正在存在的模板信息
3.3、Elasticsearch 插件安装 Elasticsearch提供插件机制对系统进行扩展以安装analysis-icu这个分词插件为例。
1、在线安装
#查看已安装插件
bin/elasticsearch-plugin list
#安装插件
bin/elasticsearch-plugin install analysis-icu
#删除插件
bin/elasticsearch-plugin remove analysis-icu 注意安装和删除完插件后需要重启ES服务才能生效。另外执行安装命令的时候需要保证 es 服务是在运行状态。 2、离线安装 本地下载相应的插件解压然后手动上传到 elasticsearch的 plugins 目录然后重启ES实例就可以了。比如 ik 中文分词插件ik分词器
unzip elasticsearch-analysis-ik-7.17.3.zip -d analysis-ik
rm elasticsearch-analysis-ik-7.17.3.zip
3、插件使用示例 测试分词效果ES 的默认分词设置是standard会单字拆分
POST _analyze
{
analyzer:standard,
text:中华人民共和国
}#ik_smart:会做最粗粒度的拆
POST _analyze
{
analyzer: ik_smart,
text: 中华人民共和国
}#ik_max_word:会将文本做最细粒度的拆分
POST _analyze
{
analyzer:ik_max_word,
text:中华人民共和国
} 创建索引时可以指定IK分词器作为默认分词器
PUT /es_db
{
settings : {
index : {
analysis.analyzer.default.type: ik_max_word
}
}
}
3.4、Elasticsearch 基本概念
1、基本术语 在7.0之前一个 Index 可以设置多个Types目前Type已经被Deprecated7.0开始一个索引只能创建一个Type - “_doc”。传统关系型数据库和Elasticsearch的区别
Elasticsearch- Schemaless /相关性/高性能全文检索RDMS —事务性/ Join 2、索引 一个索引就是一个拥有几分相似特征的文档的集合。比如说可以有一个客户数据的索引另一个产品目录的索引还有一个订单数据的索引。一个索引由一个名字来标识必须全部是小写字母的并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候都要使用到这个名字。 3、文档
Elasticsearch是面向文档的文档是所有可搜索数据的最小单位。 日志文件中的日志项一本电影的具体信息/一张唱片的详细信息MP3播放器里的一首歌/一篇PDF文档中的具体内容文档会被序列化成JSON格式保存在Elasticsearch中 JSON对象由字段组成每个字段都有对应的字段类型(字符串/数值/布尔/日期/二进制/范围类型)每个文档都有一个Unique ID 可以自己指定ID或者通过Elasticsearch自动生成一篇文档包含了一系列字段类似数据库表中的一条记录JSON文档格式灵活不需要预先定义格式 字段的类型可以指定或者通过Elasticsearch自动推算支持数组/支持嵌套 文档元数据 元数据用于标注文档的相关信息
_index文档所属的索引名_type文档所属的类型名_id文档唯—ld_source: 文档的原始Json数据version: 文档的版本号修改删除操作version都会自增1seq_no: 和version一样一旦数据发生更改数据也一直是累计的。Shard级别严格递增保证后写入的Doc的seq_no大于先写入的Doc的seq_no。primary_term: _primary_term主要是用来恢复数据时处理当多个文档的seq_no一样时的冲突避免 Primary Shard上的写入被覆盖。每当Primary Shard发生重新分配时比如重启Primary选举等_primary_term会递增1。 并发场景下修改文档 seq_no和primary_term是对version的优化7.X版本的ES默认使用这种方式控制版本所以当在高并发环境下使用乐观锁机制修改文档时要带上当前文档的seq_no和_primary_term进行更新
POST /es_db/_doc/2?if_seq_no21if_primary_term6
{
name: 李四xxx
}
如果版本号不对会抛出版本冲突异常如下图 3.5、索引的操作 创建索引 索引命名必须小写不能以下划线开头。格式: PUT /索引名称
#创建索引
PUT /es_db#创建索引时可以设置分片数和副本数
PUT /es_db
{
settings : {
number_of_shards : 3,
number_of_replicas : 2
}
}#修改索引配置
PUT /es_db/_settings
{
index : {
number_of_replicas : 1
}
} 查询索引 格式: GET /索引名称
#查询索引
GET /es_db#es_db是否存在
HEAD /es_db 删除索引 格式: DELETE /索引名称
DELETE /es_db
3.6、文档的操作 准备工作 PUT /es_db
{
settings : {
index : {
analysis.analyzer.default.type: ik_max_word
}
}
}PUT /es_db/_doc/1
{
name: 张三,
sex: 1,
age: 25,
address: 广州天河公园,
remark: java developer
}PUT /es_db/_doc/2
{
name: 李四,
sex: 1,
age: 28,
address: 广州荔湾大厦,
remark: java assistant
}PUT /es_db/_doc/3
{
name: 王五,
sex: 0,
age: 26,
address: 广州白云山公园,
remark: php developer
}PUT /es_db/_doc/4
{
name: 赵六,
sex: 0,
age: 22,
address: 长沙橘子洲,
remark: python assistant
}PUT /es_db/_doc/5
{
name: 张龙,
sex: 0,
age: 19,
address: 长沙麓谷企业广场,
remark: java architect assistant
}PUT /es_db/_doc/6
{
name: 赵虎,
sex: 1,
age: 32,
address: 长沙麓谷兴工国际产业园,
remark: java architect
}1、添加文档
格式: [PUT | POST] /索引名称/[_doc | _create ]/id
# 创建文档,指定id
# 如果id不存在创建新的文档否则先删除现有文档再创建新的文档版本会增加
PUT /es_db/_doc/1
{
name: 张三,
sex: 1,
age: 25,
address: 广州天河公园,
remark: java developer
}#创建文档ES生成id
POST /es_db/_doc
{
name: 张三,
sex: 1,
age: 25,
address: 广州天河公园,
remark: java developer
} 注意:POST和PUT都能起到创建/更新的作用PUT需要对一个具体的资源进行操作也就是要确定id才能进行更新/创建而POST是可以针对整个资源集合进行操作的如果不写id就由ES生成一个唯一id进行创建新文档如果填了id那就针对这个id的文档进行创建/更新 Create -如果ID已经存在会失败 2、修改文档 全量更新 全量更新整个json都会替换格式: [PUT | POST] /索引名称/_doc/id。如果文档存在现有文档会被删除新的文档会被索引
# 全量更新替换整个json
PUT /es_db/_doc/1/
{
name: 张三,
sex: 1,
age: 25
}#查询文档
GET /es_db/_doc/1 部分更新 使用 update 部分更新格式: POST /索引名称/update/id。update不会删除原来的文档而是实现真正的数据更新
# 部分更新在原有文档上更新
# Update -文档必须已经存在更新只会对相应字段做增量修改
POST /es_db/_update/1
{
doc: {
age: 28
}
}#查询文档
GET /es_db/_doc/1 查询并更新 使用 _update_by_query 更新文档
POST /es_db/_update_by_query
{
query: {
match: {
_id: 1
}
},
script: {
source: ctx._source.age 30
}
} 3、查询文档 根据id查询文档格式: GET /索引名称/_doc/id GET /es_db/_doc/1 条件查询 search格式 /索引名称/doc/_search # 查询前10条文档
GET /es_db/_doc/_search ES Search API提供了两种条件查询搜索方式
REST风格的请求URI直接将参数带过去封装到request body中这种方式可以定义更加易读的JSON格式
#通过URI搜索使用“q”指定查询字符串“query string syntax” KV键值对
#条件查询, 如要查询age等于28岁的 _search?q*:***
GET /es_db/_doc/_search?qage:28#范围查询, 如要查询age在25至26岁之间的 _search?q***[** TO **] 注意: TO 必须为大写
GET /es_db/_doc/_search?qage[25 TO 26]#查询年龄小于等于28岁的 :
GET /es_db/_doc/_search?qage:28#查询年龄大于28前的 :
GET /es_db/_doc/_search?qage:28#分页查询 from*size*
GET /es_db/_doc/_search?qage[25 TO 26]from0size1#对查询结果只输出某些字段 _source字段,字段
GET /es_db/_doc/_search?_sourcename,age#对查询结果排序 sort字段:desc/asc
GET /es_db/_doc/_search?sortage:desc
4、删除文档
格式: DELETE /索引名称/_doc/id
DELETE /es_db/_doc/1
5、批量写入 批量对文档进行写操作是通过_bulk的API来实现的
请求方式POST请求地址_bulk请求参数通过_bulk操作文档一般至少有两行参数(或偶数行参数) 第一行参数为指定操作的类型及操作的对象(index,type和id)第二行参数才是操作的数据
{actionName:{_index:indexName, _type:typeName,_id:id}}
{field1:value1, field2:value2}
{actionName:{_index:indexName, _type:typeName,_id:id}}
{field1:value1, field2:value2}
actionName表示操作类型主要有create,index,delete和update
5.1、批量创建文档
POST _bulk
{create:{_index:article, _type:_doc, _id:3}}
{id:3,title:fox老师,content:fox老师666,tags:[java, 面向对
象],create_time:1554015482530}
{create:{_index:article, _type:_doc, _id:4}}
{id:4,title:mark老师,content:mark老师NB,tags:[java, 面向对
象],create_time:1554015482530} 如果是已经存在的文档则会产生冲突 5.2、普通创建或全量替换
POST _bulk
{index:{_index:article, _type:_doc, _id:3}}
{id:3,title:图灵徐庶老师,content:图灵学院徐庶老师666,tags:[java, 面向对象],create_time:1554015482530}
{index:{_index:article, _type:_doc, _id:4}}
{id:4,title:图灵诸葛老师,content:图灵学院诸葛老师NB,tags:[java, 面向对象],create_time:1554015482530}GET /article/_search 如果原文档不存在则是创建如果原文档存在则是替换(全量修改原文档)
5.3、批量修改
POST _bulk
{update:{_index:article, _type:_doc, _id:3}}
{doc:{title:ES大法必修内功}}
{update:{_index:article, _type:_doc, _id:4}}
{doc:{create_time:1554018421008}}GET /article/_search 5.4、批量删除
POST _bulk
{delete:{_index:article, _type:_doc, _id:3}}
{delete:{_index:article, _type:_doc, _id:4}}GET /article/_search
5.5、组合使用
POST _bulk
{delete:{_index:article, _type:_doc, _id:3}}
{create:{_index:article, _type:_doc, _id:3}}
{title:fox老师,content:fox老师666,tags:[java, 面向对象],create_time:1554015482530}
{update:{_index:article, _type:_doc, _id:4}}
{doc:{create_time:1554018421008}}GET /article/_search
6、批量读取 es的批量查询可以使用mget和msearch两种。其中mget是需要我们知道它的id可以指定不同的 index也可以指定返回值source。msearch可以通过字段查询来进行一个批量的查找。
6.1、_mget
#可以通过ID批量获取不同index和type的数据
GET _mget
{
docs: [
{
_index: es_db,
_id: 1
},
{
_index: article,
_id: 4
}
]
}#可以通过ID批量获取es_db的数据
GET /es_db/_mget
{
docs: [
{
_id: 1
},
{
_id: 4
}
]
}#简化后
GET /es_db/_mget
{
ids:[1,2]
} 6.2、_msearch 在_msearch中请求格式和bulk类似。查询一条数据需要两个对象第一个设置index和type第二个设置查询语句。查询语句和search相同。如果只是查询一个index我们可以在url中带上index这样如果查该index可以直接用空对象表示。 4、Es 检索原理分析
4.1、索引的原理 索引是加速数据查询的重要手段其核心原理是通过不断的缩小想要获取数据的范围来筛选出最终想要的结果同时把随机的事件变成顺序的事件。
4.2、磁盘IO与预读 磁盘IO是程序设计中非常高昂的操作也是影响程序性能的重要因素因此应当尽量避免过多的磁盘IO有效的利用内存可以大大的提升程序的性能。在操作系统层面发生一次IO时不光把当前磁盘地址的数据而是把相邻的数据也都读取到内存缓冲区内局部预读性原理告诉我们当计算机访问一个地址的数据的时候与其相邻的数据也会很快被访问到。每一次IO读取的数据我们称之为一页(page)。具体一页有多大数据跟操作系统有关一般为4k或8k也就是我们读取一页内的数据时候实际上才发生了一次IO这个理论对于索引的数据结构设计非常有帮助。
4.3、Es 倒排索引 当数据写入 ES 时数据将会通过 分词 被切分为不同的 termES 将 term 与其对应的文档列表建立一种映射关系这种结构就是 倒排索引。如下图所示 为了进一步提升索引的效率ES 在 term 的基础上利用 term 的前缀或者后缀构建了 term index, 用于对 term 本身进行索引ES 实际的索引结构如下图所示 这样当我们去搜索某个关键词时ES 首先根据它的前缀或者后缀迅速缩小关键词的在 term dictionary 中的范围大大减少了磁盘IO的次数
单词词典Term Dictionary) 记录所有文档的单词记录单词到倒排列表的关联关系倒排列表(Posting List)-记录了单词对应的文档结合由倒排索引项组成倒排索引项(Posting) 文档ID词频TF–该单词在文档中出现的次数用于相关性评分位置(Position)-单词在文档中分词的位置。用于短语搜索match phrase query)偏移(Offset)-记录单词的开始结束位置实现高亮显示 5、Es 高级查询 Query DSL ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSLDomain Specified Language, Query DSL是利用Rest API传递JSON格式的请求体(RequestBody)数据与ES进行交互这种方式的丰富查询语法让ES检索变得更强大更简洁。
GET /es_db/_doc/_search {json请求体数据}#可以简化为下面写法
GET /es_db/_search {json请求体数据}
5.1、准备工作
#指定ik分词器
PUT /es_db
{
settings : {
index : {
analysis.analyzer.default.type: ik_max_word
}
}
}# 创建文档,指定id
PUT /es_db/_doc/1
{
name: 张三,
sex: 1,
age: 25,
address: 广州天河公园,
remark: java developer
}PUT /es_db/_doc/2
{
name: 李四,
sex: 1,
age: 28,
address: 广州荔湾大厦,
remark: java assistant
}PUT /es_db/_doc/3
{
name: 王五,
sex: 0,
age: 26,
address: 广州白云山公园,
remark: php developer
}PUT /es_db/_doc/4
{
name: 赵六,
sex: 0,
age: 22,
address: 长沙橘子洲,
remark: python assistant
}PUT /es_db/_doc/5
{
name: 张龙,
sex: 0,
age: 19,
address: 长沙麓谷企业广场,
remark: java architect assistant
}PUT /es_db/_doc/6
{
name: 赵虎,
sex: 1,
age: 32,
address: 长沙麓谷兴工国际产业园,
remark: java architect
}
5.2、match_all 查询 使用match_all默认只会返回10条数据。原因_search查询默认采用的是分页查询每页记录数size的默认值为10。如果想显示更多数据指定 size
GET /es_db/_search#等同于
GET /es_db/_search
{
query:{
match_all:{}
}
}
1、返回指定条数 size
GET /es_db/_search
{size: 3
} 2、分页查询 from from 关键字: 用来指定起始返回位置和size关键字连用可实现分页效果
GET /es_db/_search
{query: {match_all: {}},size: 5,from: 0
} 思考 size可以无限增加吗 GET /es_db/_search
{size: 10001
} 原因
、查询结果的窗口太大from size的结果必须小于或等于10000而当前查询结果的窗口为 10001。可以采用scroll api更高效的请求大量数据集。查询结果的窗口的限制可以通过参数index.max_result_window进行设置。
PUT /es_db/_settings
{
index.max_result_window :20000
}#修改现有所有的索引但新增的索引还是默认的10000
PUT /_all/_settings
{
index.max_result_window :20000
}#查看所有索引中的index.max_result_window值
GET /_all/_settings/index.max_result_window 参数index.max_result_window主要用来限制单次查询满足查询条件的结果窗口的大小窗口大小由from size共同决定。不能简单理解成查询返回给调用方的数据量。这样做主要是为了限制内存的消耗。 比如from为1000000size为10逻辑意义是从满足条件的数据中取1000000到1000000 10的记录。这时ES一定要先将1000000 10的记录即result_window加载到内存中再进行分页取值的操作。尽管最后我们只取了10条数据返回给客户端但ES进程执行查询操作的过程中确需要将1000000 10的记录都加载到内存中可想而知对内存的消耗有多大。这也是ES中不推荐采用from size方式进行深度分页的原因。 同理from为0size为1000000时ES进程执行查询操作的过程中确需要将1000000 条记录都加载到内存中再返回给调用方也会对ES内存造成很大压力。
3、分页查询 scroll 改动index.max_result_window参数值的大小只能解决一时的问题当索引的数据量持续增长时在查询全量数据时还是会出现问题。而且会增加ES服务器内存大结果集消耗完的风险。最佳实践还是根据异常提示中的采用scroll api更高效的请求大量数据集。
#查询命令中新增scroll1m,说明采用游标查询保持游标查询窗口一分钟。
#这里由于测试数据量不够所以size值设置为2。
#实际使用中为了减少游标查询的次数可以将值适当增大比如设置为1000。
GET /es_db/_search?scroll1m
{query: {match_all: {}},size: 2
} 除了返回前2条记录还返回了一个游标ID值_scroll_id。然后采用游标id查询
# scroll_id 的值就是上一个请求中返回的 _scroll_id 的值
GET /_search/scroll
{
scroll: 1m,
scroll_id :FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmVkNS1GTmZJVFh5d0dkQVhrLW9TZncAAAAAAAAMxxZaZ0JWdTZyVFRTeVQtdGVXMzVBZEF3
} 多次根据scroll_id游标查询直到没有数据返回则结束查询。采用游标查询索引全量数据更安全高效限制了单次对内存的消耗。
4、指定字段 sort 注意会让得分失效 GET /es_db/_search
{query: {match_all: {}},sort: [{age: desc}]
}#排序分页
GET /es_db/_search
{query: {match_all: {}},sort: [{age: desc}],from: 0,size: 5
} 5、查询返回指定字段
_source 关键字: 是一个数组,在数组中用来指定展示那些字段
GET /es_db/_search
{query: {match_all: {}},_source: [name,address]
}
5.3、match 查询 match在匹配时会对所查找的关键词进行分词然后按分词匹配查找。match支持以下参数
query : 指定匹配的值operator : 匹配条件类型 and : 条件分词后都要匹配or : 条件分词后有一个匹配即可(默认)minmum_should_match : 最低匹配度即条件在倒排索引中最低的匹配度
#模糊匹配 match 分词后or的效果
GET /es_db/_search
{query: {match: {address: 广州白云山公园}}
}POST _analyze
{analyzer:standard,text:广州白云山公园
}POST _analyze
{analyzer: ik_smart,text: 广州白云山公园
} #模糊匹配 match 分词后 and的效果
GET /es_db/_search
{query: {match: {address: {query: 广州白云山公园,operator: and}}}
} 在match中的应用 当operator参数设置为or时minnum_should_match参数用来控制匹配的分词的最少数量。
# 最少匹配广州公园两个词
GET /es_db/_search
{query: {match: {address: {query: 广州公园,minimum_should_match: 2}}}
} 5.4、短语查询 match_phrase match_phrase 查询分析文本并根据分析的文本创建一个短语查询。match_phrase 会将检索关键词分词。match_phrase的分词结果必须在被检索字段的分词中都包含而且顺序必须相同而且默认必须都是连续的。
GET /es_db/_search
{query: {match_phrase: {address: 广州白云山}}
}GET /es_db/_search
{query: {match_phrase: {address: 广州白云}}
} 思考为什么查询广州白云山有数据广州白云没有数据 分析原因 先查看广州白云山公园分词结果可以知道广州和白云不是相邻的词条中间会隔一个白云山而match_phrase匹配的是相邻的词条所以查询广州白云山有结果但查询广州白云没有结果。
POST _analyze
{analyzer: ik_max_word,text: 广州白云山
}#分析结果
{tokens : [{token : 广州,start_offset : 0,end_offset : 2,type : CN_WORD,position : 0},{token : 白云山,start_offset : 2,end_offset : 5,type : CN_WORD,position : 1},{token : 白云,start_offset : 2,end_offset : 4,type : CN_WORD,position : 2},{token : 云山,start_offset : 3,end_offset : 5,type : CN_WORD,position : 3}]
}解决办法 如何解决词条间隔的问题可以借助slop参数slop参数告诉match_phrase查询词条能够相隔多远时仍然将文档视为匹配。
#广州云山分词后相隔为2可以匹配到结果
GET /es_db/_search
{query: {match_phrase: {address: {query: 广州云山,slop: 2}}}
} 5.5、多字段查询 multi_match
可以根据字段类型决定是否使用分词查询得分最高的在前面
GET /es_db/_search
{query: {multi_match: {query: 长沙张龙,fields: [address,name]}}
} 注意字段类型分词,将查询条件分词之后进行查询如果该字段不分词就会将查询条件作为整体进行查询
5.6、query_string 查询 允许我们在单个查询字符串中指定AND | OR | NOT条件同时也和 multi_match query 一样支持多字段搜索。和match类似但是match需要指定字段名query_string是在所有字段中搜索范围更广泛。
1、未指定字段查询
GET /es_db/_search
{query: {query_string: {query: 张三 OR 橘子洲}}
} 2、指定单个字段查询
GET /es_db/_search
{query: {query_string: {default_field: address,query: 白云山 OR 橘子洲}}
} 3、指定多个字段查询
GET /es_db/_search
{query: {query_string: {fields: [name,address],query: 张三 OR (广州 AND 王五)}}
} 4、simple_query_string 查询 类似Query String但是会忽略错误的语法,同时只支持部分查询语法不支持AND OR NOT会当作字符串处理。支持部分逻辑
【】替代AND【|】替代OR【-】替代NOT
#simple_query_string 默认的operator是OR
GET /es_db/_search
{query: {simple_query_string: {fields: [name,address],query: 广州公园,default_operator: AND}}
}GET /es_db/_search
{query: {simple_query_string: {fields: [name,address],query: 广州公园}}
} 5.7、term 关键词查询 Term用来使用关键词查询(精确匹配),还可以用来查询没有被进行分词的数据类型。Term是表达语意的最小单位搜索和利用统计语言模型进行自然语言处理都需要处理Term。match在匹配时会对所查找的关键词进行分词然后按分词匹配查找而term会直接对关键词进行查找。一般模糊查找的时候多用match而精确查找时可以使用term。
ES中默认使用分词器为标准分词器(StandardAnalyzer),标准分词器对于英文单词分词,对于中文单字分词。在ES的Mapping Type 中 keyword , date ,integer, long , double , boolean or ip 这些类型不分 词只有text类型分词。
#关键字查询 term
# 思考 查询广州白云是否有数据为什么
GET /es_db/_search
{query: {term: {address: {value: 广州白云}}}
}# 采用term精确查询, 查询字段映射类型为keyword
GET /es_db/_search
{query: {term: {address.keyword: {value: 广州白云山公园}}}
} 在ES中Term查询对输入不做分词。会将输入作为一个整体在倒排索引中查找准确的词项并且使用相关度算分公式为每个包含该词项的文档进行相关度算分。
PUT /product/_bulk
{index:{_id:1}}
{productId:xxx123,productName:iPhone}
{index:{_id:2}}
{productId:xxx111,productName:iPad}# 思考 查询iPhone可以查到数据吗
GET /product/_search
{query: {term: {productName: {value: iPhone}}}
}GET /product/_analyze
{analyzer: standard,text: iPhone
} 其实查询 iPhone 没有数据的原因很简单根据 分词 可以知道 es 将【iPhone】分词成了【iphone】了而使用 term 查询是精确查询当然也包括大小写问题了 。 此外可以通过 Constant Score 将查询转换成一个 Filtering避免算分并利用缓存提高性能。
将Query 转成 Filter忽略TF-IDF计算避免相关性算分的开销Filter可以有效利用缓存
GET /es_db/_search
{query: {constant_score: {filter: {term: {address.keyword: 广州白云山公园}}}}
} 需要注意的是 term 查询 是包含而不是 等于。
POST /employee/_bulk
{index:{_id:1}}
{name:小明,interest:[跑步,篮球]}
{index:{_id:2}}
{name:小红,interest:[跳舞,画画]}
{index:{_id:3}}
{name:小丽,interest:[跳舞,唱歌,跑步]}POST /employee/_search
{query: {term: {interest.keyword: {value: 跑步}}}
} 5.8、 prefix 前缀搜索
它会对分词后的 term 进行前缀搜索。
它不会分析要搜索字符串传入的前缀就是想要查找的前缀默认状态下前缀查询不做相关度分数计算它只是将所有匹配的文档返回然后赋予所有相关分数值为1。它的行为更像是一个过滤器而不是查询。两者实际的区别就是过滤器是可以被缓存的而前缀查询不行。
prefix的原理需要遍历所有倒排索引并比较每个term是否已有所指定的前缀开头。
GET /es_db/_search
{query: {prefix: {address: {value: 广州白云}}}
}
5.9、通配符查询 wildcard 通配符查询工作原理和prefix相同只不过它不是只比较开头它能支持更为复杂的匹配模式。
GET /es_db/_search
{query: {wildcard: {address: {value: *白*}}}
} 5.10、范围查询 range
range范围关键字gte 大于等于lte 小于等于gt 大于lt 小于now 当前时间
POST /es_db/_search
{query: {range: {age: {gte: 25,lte: 28}}}
}POST /es_db/_search
{query: {range: {age: {gte: 25,lte: 28}}},from: 0,size: 2,_source: [name,age,book],sort: {age: desc}
}#日期范围查询
DELETE /productPOST /product/_bulk
{index:{_id:1}}
{price:100,date:2021-01-01,productId:XHDK-1293}
{index:{_id:2}}
{price:200,date:2022-01-01,productId:KDKE-5421}GET /product/_mappingGET /product/_search
{query: {range: {date: {gte: now-2y}}}
} 常用时间范围查询主要有以下几种方式 1、使用内置的时间数学表达式 Elasticsearch 中时间可以表示为 now也就是系统当前时间也可以是以 || 结尾的日期字符串表示。在日期之后可以选择一个或多个数学表达式。 1h表示加1小时-1d表示减1天/d四舍五入到最近的一天 表达式含义表达式含义y年M月w星期d天h小时H小时m分钟s秒 假设系统当前时间 now 2018-10-01 12:00:00 now1h: now的毫秒值 1小时, 结果是: 2018-10-01 13:00:00.now-1h: now的毫秒值 - 1小时, 结果是: 2018-10-01 11:00:00.now-1h/d: now的毫秒值 - 1小时, 然后四舍五入到最近的一天的起始, 结果是: 2018-10-01 00:00:00.2018.10.01||1M/d: 2018-10-01的毫秒值 1月, 再四舍五入到最近一天的起始, 结果是: 2018-11-01 00:00:00 关于时间的四舍五入 “gt”: 2014-11-18||/M —— 大于日期, 需要向上舍入, 结果是 2014-12-01T00:00:00.000, 也就是不包含整个11月.“gte”: “2014-11-18||/M” —— 大于或等于日期, 需要向下舍入, 结果是 2014-11-01T00:00:00.000, 也就是包含整个11月.“lt”: “2014-11-18||/M” —— 小于日期, 需要向上舍入, 结果是2014-10-31T23:59:59.999, 也就是不包含整个11月.“lte”: “2014-11-18||/M” —— 小于或等于日期, 需要向下舍入, 结果是2014-11-30T23:59:59.999, 也就是包含整个11月. 2、日期格式化范围查询 格式化日期查询时, 将默认使用日期field中指定的格式进行解析, 当然也可以通过format参数来覆盖默认配置.示例如下 GET website/_search
{query: {range: {post_date: {gte: 2/1/2018, lte: 2019,format: dd/MM/yyyy||yyyy \\这里的||表示或}}}
} 注意: 如果日期中缺失了部分年、月、日, 缺失的部分将被填充为如下默认值 MONTH_OF_YEAR: 01
DAY_OF_MONTH: 01
HOUR_OF_DAY: 23
MINUTE_OF_HOUR: 59
SECOND_OF_MINUTE: 59
NANO_OF_SECOND: 999_999_999 3、QueryString 查询 QueryString查询也可以实现时间范围查询。这种方式比较简单直接在查询语句中指定属性和时间范围即可。 {query: {query_string: {query: created_at:[2022-06-01T00:00:00.000Z TO 2022-06-01T23:59:59.999Z]}}
} 4、Date Range 聚合查询 如果需要在ES中进行时间范围的聚合分析可以使用Date Range聚合。 {aggs: {name: {date_range: {field: created_at,ranges: [{from: 2022-06-01T00:00:00.000Z,to: 2022-06-01T23:59:59.999Z},{from: 2022-06-02T00:00:00.000Z,to: 2022-06-02T23:59:59.999Z}]}}}
} 5.11、根据主键ID查询
ids 关键字 : 值为数组类型,用来根据一组id获取多个对应的文档
GET /es_db/_search
{query: {ids: {values: [1,2]}}
} 5.12、模糊查询 fuzzy 在实际的搜索中我们有时候会打错字从而导致搜索不到。在Elasticsearch中我们可以使用 fuzziness 属性来进行模糊查询从而达到搜索有错别字的情形。fuzzy 查询会用到两个很重要的参数fuzzinessprefix_length
fuzziness表示输入的关键字通过几次操作可以转变成为ES库里面的对应field的字段 操作是指新增一个字符删除一个字符修改一个字符每次操作可以记做编辑距离为1如中文集团到中威集团编辑距离就是1只需要修改一个字符该参数默认值为0即不开启模糊查询。如果fuzziness值在这里设置成2会把编辑距离为2的东东集团也查出来。prefix_length表示限制输入关键字和ES对应查询field的内容开头的第n个字符必须完全匹配不允许错别字匹配 如这里等于1则表示开头的字必须匹配不匹配则不返回默认值也是0加大prefix_length的值可以提高效率和准确率。
GET /es_db/_search
{query: {fuzzy: {address: {value: 白运山,fuzziness: 1,prefix_length: 0}}}
}
注意: fuzzy 模糊查询 最大模糊错误 必须在0-2之间
搜索关键词长度为 2不允许存在模糊搜索关键词长度为3-5允许1次模糊搜索关键词长度大于5允许最大2次模糊
5.13、高亮查询 highlight highlight 关键字: 可以让符合条件的文档中的关键词高亮。主要有以下这些属性
pre_tags 前缀标签post_tags 后缀标签tags_schema 设置为styled可以使用内置高亮样式require_field_match 多字段高亮需要设置为false
1、准备工作
#指定ik分词器
PUT /products
{settings: {index: {analysis.analyzer.default.type: ik_max_word}}
}PUT /products/_doc/1
{proId: 2,name: 牛仔男外套,desc: 牛仔外套男装春季衣服男春装夹克修身休闲男生潮牌工装潮流头号青年春秋棒球服男 7705浅蓝常规 XL,timestamp: 1576313264451,createTime: 2019-12-13 12:56:56
}PUT /products/_doc/1
{proId: 6,name: HLA海澜之家牛仔裤男,desc: HLA海澜之家牛仔裤男2019时尚有型舒适HKNAD3E109A 牛仔蓝(A9)175/82A(32),timestamp: 1576314265571,createTime: 2019-12-18 15:56:56
} 2、自定义高亮 html 标签 可以在highlight中使用pre_tags和post_tags
GET /products/_search
{query: {term: {name: {value: 牛仔}}},highlight: {post_tags: [/span],pre_tags: [span stylecolor:red],fields: {*: {}}}
} 3、多字段高亮
GET /products/_search
{query: {term: {name: {value: 牛仔}}},highlight: {pre_tags: [font colorred],post_tags: [font/],require_field_match: false,fields: {name: {},desc: {}}}
} 5.14、相关性与相关性算分
搜索是用户和搜索引擎的对话用户关心的是搜索结果的相关性
是否可以找到所有相关的内容有多少不相关的内容被返回了文档的打分是否合理结合业务需求平衡结果排名
如何衡量相关性
Precision(查准率)―尽可能返回较少的无关文档Recall(查全率)–尽量返回较多的相关文档Ranking -是否能够按照相关度进行排序
1、相关性 搜索的相关性算分描述了一个文档和查询语句匹配的程度。ES 会对每个匹配查询条件的结果进行算分_score。 打分的本质是排序需要把最符合用户需求的文档排在前面。ES 5之前默认的相关性算分采用TFIDF现在采用BM 25。
关键词文档IDJAVA1,2,3设计模式1,2,3,4,5,6多线程2,3,7,9
2、什么是 TF-IDF TF-IDFterm frequency–inverse document frequency是一种用于信息检索与数据挖掘的常用加权技术。
TF-IDF被公认为是信息检索领域最重要的发明除了在信息检索在文献分类和其他相关领域有着非常广泛的应用。IDF的概念最早是剑桥大学的“斯巴克.琼斯”提出 1972年——“关键词特殊性的统计解释和它在文献检索中的应用”但是没有从理论上解释IDF应该是用log(全部文档数/检索词出现过的文档总数)而不是其他函数也没有做进一步的研究19701980年代萨尔顿和罗宾逊进行了进一步的证明和研究并用香农信息论做了证明 香农信息论现代搜索引擎对TF-IDF进行了大量细微的优化 Lucene 中的 TF-IDF 评分公式 TF是词频(Term Frequency)检索词在文档中出现的频率越高相关性也越高。IDF是逆向文本频率(Inverse Document Frequency)每个检索词在索引中出现的频率频率越高相关性越低。字段长度归一值 field-length norm字段的长度是多少字段越短字段的权重越高。检索词出现在一个内容短的 title 要比同样的词出现在一个内容长的 content 字段权重更大。 以上三个因素——词频term frequency、逆向文档频率inverse document frequency和字段长度归一值field-length norm——是在索引时计算并存储的最后将它们结合在一起计算单个词在特定文档中的权重。
3、什么是 BM25
从ES 5开始默认算法改为BM 25和经典的TF-IDF相比,当TF无限增加时BM 25算分会趋于一个数值 BM 25 公式 4、通过 Explain API 查看 TF-IDF
PUT /test_score/_bulk
{index:{_id:1}}
{content:we use Elasticsearch to power the search}
{index:{_id:2}}
{content:we like elasticsearch}
{index:{_id:3}}
{content:Thre scoring of documents is caculated by the scoring formula}
{index:{_id:4}}
{content:you know,for search}GET /test_score/_search
{explain: true,query: {match: {content: elasticsearch}}
} 5、Bootsting Relevance
Boosting是控制相关度的一种手段。参数boost的含义
当boost 1时打分的相关度相对性提升当0 boost 1时打分的权重相对性降低当boost 0时贡献负分 返回匹配 positive 查询的文档并降低匹配 negative 查询的文档相似度分。这样就可以在不排除某些文档的前提下对文档进行查询,搜索结果中存在只不过相似度分数相比正常匹配的要低;
GET /test_score/_search
{query: {boosting: {positive: {term: {content: elasticsearch}},negative: {term: {content: like}},negative_boost: 0.2}}
} 5.15、布尔查询 bool Query 一个bool查询,是一个或者多个查询子句的组合总共包括4种子句其中2种会影响算分2种不影响算分。
must: 相当于 必须匹配贡献算分should: 相当于|| 选择性匹配贡献算分must_not: 相当于! 必须不能匹配不贡献算分filter: 必须匹配不贡献算法
在Elasticsearch中有Query和 Filter两种不同的Context
Query Context: 相关性算分Filter Context: 不需要算分( Yes or No) ,可以利用Cache获得更好的性能 相关性并不只是全文本检索的专利也适用于yes | no 的子句匹配的子句越多相关性评分 越高。如果多条查询子句被合并为一条复合查询语句比如 bool查询则每个查询子句计算得出的评分会被合并到总的相关性评分中。 bool查询语法 子查询可以任意顺序出现可以嵌套多个查询如果你的bool查询中没有must条件,should中必须至少满足一条查询
GET /es_db/_search
{query: {bool: {must: {match: {remark: java developer}},filter: {term: {sex: 1}},must_not: {range: {age: {gte: 30}}},should: [{term: {address.keyword: {value: 广州天河公园}}},{term: {address.keyword: {value: 广州白云山公园}}}],minimum_should_match: 1}}
}
1、解决结构化查询 “包含而不是相等” 的问题 数据准备 POST /employee/_bulk
{index:{_id:1}}
{name:小明,interest:[跑步,篮球]}
{index:{_id:2}}
{name:小红,interest:[跑步]}
{index:{_id:3}}
{name:小丽,interest:[跳舞,唱歌,跑步]}POST /employee/_search
{query: {term: {interest.keyword: {value: 跑步}}}
}
解决方案增加count字段使用bool查询解决
从业务角度按需改进Elasticsearch数据模型
POST /employee/_bulk
{index:{_id:1}}
{name:小明,interest:[跑步,篮球],interest_count:2}
{index:{_id:2}}
{name:小红,interest:[跑步],interest_count:1}
{index:{_id:3}}
{name:小丽,interest:[跳舞,唱歌,跑步],interest_count:3}
使用bool查询
# must 算分
POST /employee/_search
{query: {bool: {must: [{term: {interest.keyword: {value: 跑步}}},{term: {interest_count: {value: 1}}}]}}
}# filter不算分
POST /employee/_search
{query: {bool: {filter: [{term: {interest.keyword: {value: 跑步}}},{term: {interest_count: {value: 1}}}]}}
}
2、利用 bool 嵌套实现 should not 逻辑
GET /es_db/_search
{query: {bool: {must: {match: {remark: java developer}},should: [{bool: {must_not: [{term: {sex: 1}}]}}],minimum_should_match: 1}}
} 3、控制字段的Boosting Boosting是控制相关度的一种手段。可以通过指定字段的boost值影响查询结果。参数boost的含义
当boost 1时打分的相关度相对性提升当0 boost 1时打分的权重相对性降低当boost 0时贡献负分
POST /blogs/_bulk
{index:{_id:1}}
{title:Apple iPad,content:Apple iPad,Apple iPad}
{index:{_id:2}}
{title:Apple iPad,Apple iPad,content:Apple iPad}GET /blogs/_search
{query: {bool: {should: [{match: {title: {query: apple,ipad,boost: 1}}},{match: {content: {query: apple,ipad,boost: 4}}}]}}
} 案例要求苹果公司的产品信息优先展示 POST /news/_bulk
{index:{_id:1}}
{content:Apple Mac}
{index:{_id:2}}
{content:Apple iPad}
{index:{_id:3}}
{content:Apple employee like Apple Pie and Apple Juice}GET /news/_search
{query: {bool: {must: {match: {content: apple}}}}
} 利用must not 排除不是苹果公司产品的文档 GET /news/_search
{query: {bool: {must: {match: {content: apple}},must_not: {match: {content: pie}}}}
} 利用 negative boost 降低相关性 negative_boost 对 negative部分query生效计算评分时,boosting部分评分不修改negative部分query乘以negative_boost值negative_boost取值:0-1.0举例:0.3 对某些返回结果不满意但又不想排除掉 must_not)可以考虑boosting query的negative_boost。
GET /news/_search
{query: {boosting: {positive: {match: {content: apple}},negative: {match: {content: pie}},negative_boost: 0.2}}
} 5.16、文档映射 mapping
Mapping类似数据库中的schema的定义作用如下
定义索引中的字段的名称定义字段的数据类型例如字符串数字布尔等字段倒排索引的相关配置(Analyzed or Not Analyzed,Analyzer)
ES中Mapping映射可以分为动态映射和静态映射。 动态映射 在关系数据库中需要事先创建数据库然后在该数据库下创建数据表并创建表字段、类型、长度、主键等最后才能基于表插入数据。而Elasticsearch中不需要定义Mapping映射即关系型数据库的表、字段等在文档写入Elasticsearch时会根据文档字段自动识别类型这种机制称之为动态映射。 静态映射 静态映射是在Elasticsearch中也可以事先定义好映射包含文档的各字段类型、分词器等这种方式称之为静态映射。 动态映射Dynamic Mapping的机制使得我们无需手动定义MappingsElasticsearch会自动根据文档信息推算出字段的类型。但是有时候会推算的不对例如地理位置信息。当类型如果设置不对时会导致一些功能无法正常运行例如Range查询 Dynamic Mapping类型自动识别 JSON类型Elasticsearch类型字符串 匹配日期格式设置成 Date 匹配数字则设置为 float 或者 long该选项默认关闭 设置为text并且增加 keyword 子字段布尔值Boolean浮点数float整数long对象object数组由第一个非空数值的类型所决定空值忽略 动态映射示例 #删除原索引
DELETE /user#创建文档(ES根据数据类型, 会自动创建映射)
PUT /user/_doc/1
{name: fox,age: 32,address: 长沙麓谷
}#获取文档映射
GET /user/_mapping 思考能否后期更改Mapping的字段类型 主要有两种情况
新增加字段 dynamic设为true时一旦有新增字段的文档写入Mapping 也同时被更新dynamic设为falseMapping 不会被更新新增字段的数据无法被索引但是信息会出现在_source中dynamic设置成strict(严格控制策略)文档写入失败抛出异常
描述truefalsestrict文档可索引yesyesno字段可索引yesnonoMapping被更新yesnono
对已有字段一旦已经有数据写入就不再支持修改字段定义 Lucene 实现的倒排索引一旦生成后就不允许修改如果希望改变字段类型必须 Reindex API重建索引
原因如下
如果修改了字段的数据类型会导致已被索引的数据无法被搜索但是如果是增加新的字段就不会有这样的影响
DELETE /userPUT /user
{mappings: {dynamic: strict,properties: {name: {type: text},address: {type: object,dynamic: true}}}
}# 插入文档报错原因为age为新增字段,会抛出异常
PUT /user/_doc/1
{name: fox,age: 32,address: {province: 湖南,city: 长沙}
} 修改dynamic后再次插入文档成功
#修改daynamic
PUT /user/_mapping
{dynamic: true
}
1、对已存在 mapping 进行修改
如果要推倒现有的映射, 你得重新建立一个静态索引然后把之前索引里的数据导入到新的索引里删除原创建的索引为新索引起个别名, 为原索引名
POST _reindex
{source: {index: user},dest: {index: user2}
}DELETE /userPUT /user2/_alias/userGET /user 注意: 通过这几个步骤就实现了索引的平滑过渡,并且是零停机
2、常用 Mapping 参数配置
index: 控制当前字段是否被索引默认为true。如果设置为false该字段不可被搜索
DELETE /userPUT /user
{mappings: {properties: {address: {type: text,index: false},age: {type: long},name: {type: text}}}
}PUT /user/_doc/1
{name: fox,address: 广州白云山公园,age: 30
}GET /userGET /user/_search
{query: {match: {address: 广州}}
} 有四种不同基本的 index_options 配置控制倒排索引记录的内容 docs : 记录doc idfreqs记录doc id 和term frequencies词频positions: 记录doc id / term frequencies / term positionoffsets: doc id / term frequencies / term posistion / character offects text类型默认记录postions其他默认为 docs。记录内容越多占用存储空间越大 DELETE /userPUT /user
{mappings: {properties: {address: {type: text,index_options: offsets},age: {type: long},name: {type: text}}}
}GET /user
null_value: 需要对Null值进行搜索只有 keyword 类型支持设计Null_Value
DELETE /userPUT /user
{mappings: {properties: {address: {type: keyword,null_value: NULL},age: {type: long},name: {type: text}}}
}PUT /user/_doc/1
{name: fox,address: null,age: 30
}GET /user/_search
{query: {term: {address: NULL}}
} copy_to设置将字段的数值拷贝到目标字段满足一些特定的搜索需求。copy_to的目标字段不出现在_source中。
# 设置copy_to
PUT /address
{mappings: {properties: {province: {type: keyword,copy_to: full_address},city: {type: text,copy_to: full_address}}}
}PUT /address/_doc/1
{province: 湖南,city: 长沙
}PUT /address/_doc/2
{province: 湖南,city: 常德
}GET /address/_search
{query: {match: {full_address: {query: 湖南常德,operator: and}}}
} 3、索引模板Index Template Index Templates可以帮助你设定 Mappings 和 Settings并按照一定的规则自动匹配到新创建的索引之上
模版仅在一个索引被新创建时才会产生作用。修改模版不会影响已创建的索引你可以设定多个索引模版这些设置会被“merge”在一起你可以指定“order”的数值控制“merging”的过程
PUT /_template/template_default
{index_patterns: [*],order: 0,version: 1,settings: {number_of_shards: 1,number_of_replicas: 1}
}#date_detection: false 关闭日期探测
PUT /_template/template_test
{index_patterns: [test*],order: 1,settings: {number_of_shards: 1,number_of_replicas: 1},mappings: {date_detection: false,numeric_detection: true}
} lndex Template的工作方式 当一个索引被新创建时
应用Elasticsearch 默认的settings 和mappings应用order数值低的 lndex Template 中的设定应用order高的 Index Template 中的设定之前的设定会被覆盖应用创建索引时用户所指定的Settings和 Mappings并覆盖之前模版中的设定
#查看template信息
GET /_template/template_defaultGET /_template/temp*# 关闭日期探测createDate会推断为text类型
PUT /testtemplate/_doc/1
{orderNo: 1,createDate: 2022/01/01
}GET /testtemplate/_mappingGET /testtemplate/_settingsGET /testtemplate# 开启日期探测将会自动识别检测日期格式的字符串数值
PUT /testmy
{mappings: {date_detection: true}
}PUT /testmy/_doc/1
{orderNo: 1,createDate: 2022/01/01
}GET /testmy/_mappingGET /testmy
4、动态模板Dynamic Template
根据Elasticsearch识别的数据类型结合字段名称来动态设定字段类型
所有的字符串类型都设定成Keyword或者关闭keyword 字段is开头的字段都设置成 booleanlong_开头的都设置成 long类型
PUT /my_test_index
{mappings: {dynamic_templates: [{full_name: {path_match: name.*,path_unmatch: *.middle,mapping: {type: text,copy_to: full_name}}}]}
}PUT /my_test_index/_doc/1
{name: {first: John,middle: Winston,last: Lennon}
}GET /my_test_index/_search
{query: {match: {full_name: John}}
}