技术标签: ElasticSearch java elasticsearch 数据库 es 大数据
注:version:elasticsearch-7.11.2
造测试数据:
#新建mapping映射
PUT /developer
{
"mappings": {
"properties": {
"name": {
"type": "keyword",
"index": true,
"store": true
},
"gender": {
"type": "integer",
"index": true,
"store": true
},
"age": {
"type": "integer",
"index": true,
"store": true
},
"remark": {
"type": "text",
"index": true,
"store": true,
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"address": {
"type": "text",
"index": true,
"store": true,
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
},
"settings": {
"number_of_shards": 1,
"number_of_replicas": 1
}
}
#添加两条数据
POST _bulk
{"create":{"_index":"developer","_type":"_doc","_id":1}}
{"id":1,"name":"李雷","age":18,"gender":1,"remark":"是一个初级程序员","address": "浙江省杭州市西湖区"}
{"create":{"_index":"developer","_type":"_doc","_id":2}}
{"id":2,"name":"韩梅","age":17,"gender":0,"remark":"是一个女程序员","address": "安徽省合肥市蜀山区"}
remark分词结果:
GET /developer/_search
{
"query":{
"match": {
"remark": {
"query": "初级程序员",
"operator": "and"
}
}
}
}
"初级程序员"会被分词为"初级"和"程序员"。使用"operator": "and",就必须同时满足“初级”和“程序员”两个词。如果不写的话默认是"operator": "or"
minimum_should_match 用来控制最小匹配数量,可以是数字或百分比(例: 75%)。
GET /developer/_search
{
"query":{
"match": {
"remark": {
"query": "一个初级程序员",
"minimum_should_match": "3"
}
}
}
}
上图中的分词,可以匹配到3个词,分别是"一个"、"初级"、"程序员"。minimum_should_match 设置小于3的值都可以匹配到结果
搭配组合查询使用:
GET developer/_doc/_search
{
"query": {
"bool": {
"should": [
{
"match": {
"remark": "一个"
}
},
{
"match": {
"remark": "初级"
}
},
{
"match": {
"remark": "女"
}
},
{
"match": {
"remark": "程序员"
}
}
],
"minimum_should_match": 3
}
}
}
上图至少满足3个条件,所以把添加的两条数据都查询出来了。
在ES中,执行match搜索的时候,ES底层通常都会对搜索条件进行底层转换,把叶子查询转换为组合查询,来实现最终的搜索结果。例如:
原查询语句(没写operator时默认为or):
GET developer/_doc/_search
{
"query": {
"match": {
"remark":"初级程序员"
}
}
}
由叶子查询转换为组合查询:
GET developer/_doc/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"remark": "初级"
}
},
{
"term": {
"remark": "程序员"
}
}
]
}
}
}
原查询:
GET developer/_doc/_search
{
"query": {
"match": {
"remark": {
"query": "初级程序员",
"operator": "and"
}
}
}
}
由叶子查询转换为组合查询:
GET developer/_doc/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"remark": "初级"
}
},
{
"term": {
"remark": "程序员"
}
}
]
}
}
}
建议,如果不怕麻烦,尽量使用转换后的语法执行搜索,效率更高。如果开发周期短,工作量大,使用简化的写法。
GET developer/_doc/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"remark": "程序员"
}
}
],
"should": [
{
"match": {
"address": {
"query": "安徽省",
"boost": 2
}
}
},
{
"match": {
"address": {
"query": "浙江省",
"boost": 1
}
}
}
]
}
}
}
安徽省 和 浙江省 给的权重比例是2:1,查询结果 _score 分值安徽省更大,排在前面。
best fields策略: 搜索的document中的某一个field,尽可能多的匹配搜索条件。与之相反的是,尽可能多的字段匹配到搜索条件(most fields策略)。如百度搜索使用这种策略。
优点:精确匹配的数据可以尽可能的排列在最前端,且可以通过minimum_should_match来去除长尾数据,避免长尾数据字段对排序结果的影响。
长尾数据比如说我们搜索4个关键词,但很多文档只匹配1个,也显示出来了,这些文档其实不是我们想要的
缺点:相对排序不均匀。
dis_max语法: 直接获取搜索的多条件中的,单条件query相关度分数最高的数据,以这个数据做相关度排序。
GET /developer/_doc/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"remark": "女"
}
},
{
"match": {
"remark": "初级程序员"
}
}
]
}
}
}
以上查询的 queries 有 2 个条件,
"remark": "女" 匹配到一文档
"remark": "初级程序员" 匹配到两个文档
使用 "remark": "初级程序员" 查询的分值最高,那么"初级程序员"这条数据的分值更多,排序靠前。
dis_max 是将多个搜索query条件中相关度分数最高的用于结果排序,忽略其他query分数,在某些情况下,可能还需要其他query条件中的相关度介入最终的结果排序,这个时候可以使用 tie_breaker 参数来优化dis_max搜索。
tie_breaker 参数代表的含义是:将其他query搜索条件的相关度分数乘以参数值,再参与到结果排序中。如果不定义此参数,相当于参数值为0。所以其他query条件的相关度分数被忽略。
GET /developer/_doc/_search
{
"query": {
"dis_max": {
"queries": [
{
"match": {
"remark": "女"
}
},
{
"match": {
"remark": "初级程序员"
}
}
],
"tie_breaker":0.5
}
}
}
相比较下"韩梅"的分值有所增加
使用multi_match语法为:其中type常用的有 best_fields 和 most_fields。^n 代表权重,相当于 "boost":n
GET /developer/_doc/_search
{
"query": {
"multi_match": {
"query": "李雷一个程序员",
"fields": ["name", "remark^2"],
"type": "best_fields",
"tie_breaker": 0.5,
"minimum_should_match": 2
}
}
}
minimum_should_match是针对分词后,每个条件的匹配个数的。比如这里分词为"李雷"、"一个"、"程序员"一共3个,那么name必须匹配其中两个,或者remark必须匹配其中两个
cross fields搜索:在多个fields中搜索唯一标识的数据。例如在多个字段中搜索人名、地址。
实现这种搜索,一般都是使用most fields搜索策略。因为这就不是一个field的问题。
Cross fields搜索策略,是从多个字段中搜索条件数据。默认情况下,和most fields搜索的逻辑是一致的,计算相关度分数是和best fields策略一致的。一般来说,如果使用cross fields搜索策略,那么都会携带一个额外的参数operator。用来标记搜索条件如何在多个字段中匹配。
most field策略缺点:most fields策略是尽可能匹配更多的字段,所以会导致精确搜索结果排序问题。又因为cross fields搜索,不能使用minimum_should_match来去除长尾数据。所以在使用most fields和cross fields策略搜索数据的时候,都有不同的缺陷。所以商业项目开发中,都推荐使用best fields策略实现搜索。
GET /developer/_doc/_search
{
"query": {
"multi_match": {
"query": "浙江省杭州市西湖区",
"fields": ["name", "address"],
"type": "cross_fields",
"operator" : "and"
}
}
}
在搜索地址的时候,需要同时在省、市、街道、3个字段同时搜索,怎么做呢?
第一种方法可以使用 multi_match ,上面有写过实例。
此处讲第二种方法,使用 copy_to 组合 fields
copy_to : 就是将多个字段,复制到一个字段中,实现一个多字段组合。copy_to可以解决cross fields搜索问题,在商业项目中,也用于解决搜索条件默认字段问题。
如果需要使用copy_to语法,则需要在定义index的时候,手工指定mapping映射策略。
copy_to语法:
PUT /address/_mapping
{
"properties": {
"provice": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "address"
},
"city": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "address"
},
"street": {
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "address"
},
"address": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
以上mapping会把provice、city、street三个字段的值,会自动复制到address字段中,实现一个字段的组合。那么在搜索地址的时候,就可以在address字段中做条件匹配,从而避免most fields策略导致的问题。在维护数据的时候,不需对address字段特殊的维护。因为address字段是一个组合字段,是由ES自动维护的。类似java代码中的推导属性。在存储的时候,未必存在,但是在逻辑上是一定存在的,因为address是由3个物理存在的属性province、city、street组成的。
match phrase:短语匹配。代表搜索条件不可分割。
造测试数据:
#新建索引
PUT /test_match_phrase
#为索引添加映射
PUT /test_match_phrase/_mappings
{
"properties": {
"remark":{
"type": "text",
"analyzer": "standard"
}
}
}
#添加两条测试数据
POST /_bulk
{"create":{"_index": "test_match_phrase", "_type":"_doc", "_id": 1}}
{"id":1,"remark": "Hellow world"}
{"create":{"_index": "test_match_phrase", "_type":"_doc", "_id": 2}}
{"id":2,"remark": "Hellow daliu, I love the world"}
# Hellow world 短语匹配
GET /test_match_phrase/_search
{
"query": {
"match_phrase": {
"remark": "Hellow world"
}
}
}
如上图这样只能匹配到 id=1 的文档。
1.文档在建立的时候会进行分词,并建立倒排索引,分词结果如下:
position:以词为单位,代表这个词在整个数据中的下标。
倒排索引建立如下:(word记录分词,index 记录分词所在的文档id)
2.将搜索条件 "Hellow world" 分词为 "Hellow" 和 "world",然后在倒排索引中进行检索,匹配到文档id包含[1,2] 的两个文档,然后分别在这两个文档中检查"Hellow"和"world"的position是否连续,如果是连续的则代表成功,否则失败。此例中文档id=1的那个文档的position是连续的,所以返回了文档id=1的那条数据。
slop代表match phrase短语搜索的时候,单词最多移动多少次,可以实现数据匹配。在所有匹配结果中,多个单词距离越近,相关度评分越高,排序越靠前。
这种使用slop参数的match phrase搜索,就称为近似匹配(proximity search)
上面的查询语句加上slop参数:
GET /test_match_phrase/_search
{
"query": {
"match_phrase": {
"remark": {
"query": "Hellow world",
"slop": 4
}
}
}
}
如上图,加上slop:4的参数就可以匹配到id=2的文档
上面的 slop:4 代表可以移动4次。
原理:
搜索条件"Hellow world"被分词为"Hellow"和"world"两个,在倒排索引中匹配到文档[1,2]后,在这两个文档中检查position,在index=2的文档中会根据slop参数执行单词的移动。
如下:
移动4的时候匹配成功
GET /developer/_search
{
"query": {
"prefix": {
"address": {
"value": "浙江省"
}
}
}
}
前缀搜索效率比较低。前缀搜索不会计算相关度分数。前缀越短,效率越低。如果使用前缀搜索,建议使用长前缀。因为前缀搜索需要扫描完整的索引内容,所以前缀越长,相对效率越高。
ES中也有通配符。但是和java还有数据库不太一样。通配符可以在倒排索引中使用,也可以在keyword类型字段中使用。
常用通配符:
? - 一个任意字符
* - 0~n个任意字符
GET /test_match_phrase/_search
{
"query": {
"wildcard": {
"remark": "*da*"
}
}
}
使用通配符模糊匹配,即使在分词匹配不到的时候也能搜索到结果
性能也很低,也是需要扫描完整的索引。不推荐使用。
ES支持正则表达式。可以在倒排索引或keyword类型字段中使用。
常用符号:
[] :范围,如 [0-9]是0~9的范围数字
. : 一个字符
+ :前面的表达式可以出现多次。
GET /test_match_phrase/_search
{
"query": {
"regexp": {
"remark": "[A-z].+"
}
}
}
实现类似百度的这种效果。
match_phrase_prefix 的作用正如其名,就是 match_phrase + prefix
不但可以前缀匹配,而且可以移动词匹配
GET /test_match_phrase/_search
{
"query": {
"match_phrase_prefix": {
"remark": {
"query": "Hellow w",
"slop" : 4,
"max_expansions": 10
}
}
}
}
slop: 如同match_phrase一样,指定最大分词位数。
max_expansions: 指定prefix最多匹配多少个term(单词)。
这种语法的限制是,只有最后一个term会执行前缀搜索。
执行性能很差,毕竟最后一个term是需要扫描所有符合slop要求的倒排索引的term。
因为效率较低,如果必须使用,则一定要使用参数max_expansions。
搜索的时候可能输入错误,例如 "hellow world" 输入成了 "hellow word"。fuzzy可以让这种拼写错误也能查询数据(在英文中很有效,在中文中几乎无效)
GET /test_match_phrase/_search
{
"query": {
"fuzzy": {
"remark": {
"value": "word",
"fuzziness":2
}
}
}
}
fuzziness:允许字母误差个数。代表value的值word可以修改多少个字母来进行拼写错误的纠正(修改字母的数量包含字母变更,增加或减少字母),例如本例中的 world 去掉 l 就能匹配上,所以fuzziness = 1的时候也能查询出结果
文章浏览阅读3.8k次,点赞9次,收藏28次。直接上一个工作中碰到的问题,另外一个系统开启多线程调用我这边的接口,然后我这边会开启多线程批量查询第三方接口并且返回给调用方。使用的是两三年前别人遗留下来的方法,放到线上后发现确实是可以正常取到结果,但是一旦调用,CPU占用就直接100%(部署环境是win server服务器)。因此查看了下相关的老代码并使用JProfiler查看发现是在某个while循环的时候有问题。具体项目代码就不贴了,类似于下面这段代码。while(flag) {//your code;}这里的flag._main函数使用while(1)循环cpu占用99
文章浏览阅读347次。idea shift f6 快捷键无效_idea shift +f6快捷键不生效
文章浏览阅读135次。Ecmacript 中没有DOM 和 BOM核心模块Node为JavaScript提供了很多服务器级别,这些API绝大多数都被包装到了一个具名和核心模块中了,例如文件操作的 fs 核心模块 ,http服务构建的http 模块 path 路径操作模块 os 操作系统信息模块// 用来获取机器信息的var os = require('os')// 用来操作路径的var path = require('path')// 获取当前机器的 CPU 信息console.log(os.cpus._node模块中有很多核心模块,以下不属于核心模块,使用时需下载的是
文章浏览阅读10w+次,点赞435次,收藏3.4k次。SPSS 22 下载安装过程7.6 方差分析与回归分析的SPSS实现7.6.1 SPSS软件概述1 SPSS版本与安装2 SPSS界面3 SPSS特点4 SPSS数据7.6.2 SPSS与方差分析1 单因素方差分析2 双因素方差分析7.6.3 SPSS与回归分析SPSS回归分析过程牙膏价格问题的回归分析_化工数学模型数据回归软件
文章浏览阅读7.5k次。如何利用hutool工具包实现邮件发送功能呢?1、首先引入hutool依赖<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.7.19</version></dependency>2、编写邮件发送工具类package com.pc.c..._hutool发送邮件
文章浏览阅读867次,点赞2次,收藏2次。docker安装elasticsearch,elasticsearch-head,kibana,ik分词器安装方式基本有两种,一种是pull的方式,一种是Dockerfile的方式,由于pull的方式pull下来后还需配置许多东西且不便于复用,个人比较喜欢使用Dockerfile的方式所有docker支持的镜像基本都在https://hub.docker.com/docker的官网上能找到合..._docker安装kibana连接elasticsearch并且elasticsearch有密码
文章浏览阅读1.3w次,点赞57次,收藏92次。整理 | 郑丽媛出品 | CSDN(ID:CSDNnews)近年来,随着机器学习的兴起,有一门编程语言逐渐变得火热——Python。得益于其针对机器学习提供了大量开源框架和第三方模块,内置..._beeware
文章浏览阅读7.9k次。//// ViewController.swift// Day_10_Timer//// Created by dongqiangfei on 2018/10/15.// Copyright 2018年 飞飞. All rights reserved.//import UIKitclass ViewController: UIViewController { ..._swift timer 暂停
文章浏览阅读986次,点赞2次,收藏2次。1.硬性等待让当前线程暂停执行,应用场景:代码执行速度太快了,但是UI元素没有立马加载出来,造成两者不同步,这时候就可以让代码等待一下,再去执行找元素的动作线程休眠,强制等待 Thread.sleep(long mills)package com.example.demo;import org.junit.jupiter.api.Test;import org.openqa.selenium.By;import org.openqa.selenium.firefox.Firefox.._元素三大等待
文章浏览阅读3k次,点赞4次,收藏14次。Java软件工程师职位分析_java岗位分析
文章浏览阅读2k次。Java:Unreachable code的解决方法_java unreachable code
文章浏览阅读1w次。1、html中设置标签data-*的值 标题 11111 222222、点击获取当前标签的data-url的值$('dd').on('click', function() { var urlVal = $(this).data('ur_如何根据data-*属性获取对应的标签对象