草庐IT

Elasticsearch入门笔记(DSL搜索)

缩缩北行鸟 2024-03-28 原文

DSL 搜索

ES 使用 queryString 形式根据搜索词对索引表的文档进行检索:

GET /{indexName}/_doc/_search?q={fieldName1}:{searchTxt1}&q={fieldName2}:{searchTxt2}..

但这种 queryString 的形式查询数据只适合一些简单查询的场景,一旦参数多了就难以进行构建(需要添加分页、过滤等功能),所以多数情况下使用 DSL Domain Specific Language 进行查询更好,因为它基于 JSON 格式的数据查询,这样的可读性会更好,有利于复杂查询。

1 DSL 语法

1.1 基本搜索

  • match_all 关键字,表示 在索引中查询所有文档(上一篇文章有 queryString 查询的做法)
    • _source 关键字填充需要搜索的字段名
    • fromsize:默认的 ES 只显示10条数据,此时可以使用分页显示,from 是表示从起始索引,size 表示一页显示的个数
POST /{indexName}/_doc/_search
{
	"query": {
		"match_all": {}
	},
	"_source": [{fieldName1}, {fieldName2}...],
	"from": 1,
	"size": 5
}
  • match 关键字,将 搜索内容进行分词后搜索
    • match 关键字默认的 operator 属性是 or,即搜索内容分词后,只要存在一个词语匹配就展示结果,设置为 and 后,搜索内容分词后,都要满足词语匹配
    • minimum_should_match:最低匹配精度,比如说最低匹配精度为 70%,而搜索内容分词后有 10 个词语,则文档必须要有 10*0.7=7 个词语匹配才会符合显示需求。
POST /{indexName}/_doc/_search
// 默认 operator 为 or
{
	"query": {
		"match": {
			{fieldName}: {searchTxt}
		}
	}
}
// 设置 operator 为 true
{
    "query": {
		"match": {
			{fieldName}: {
				"query": {searchTxt},
                "operator": "and"
			}
		}
    }
}
// 最低匹配精度
{
    "query": {
		"match": {
			{fieldName}: {
				"query": {searchTxt},
				"minimum_should_match": {minimum_should_match}
			}
		}
    }
}
  • multi_match 关键字,满足使用 match 模式在多个字段属性中进行查询的需求
    • boost 权重,多字段属性查询时,可为某些字段属性设置权重,权重越高,文档相关性得分就越高,如下 {fieldName2}^{weight} 举例:"desc^10" 表示 desc 字段属性搜素提升 10 倍相关性,即如果其他字段没有设置权重,用户搜索时会以 desc 为主
POST /{indexName}/_doc/_search
{
	"query": {
		"multi_match": {
			"query": {searchTxt},
			"fields": [{fieldName1}, {fieldName2}...]
		}
	}
}
// 设置权重
{
	"query": {
		"multi_match": {
			"query": {searchTxt},
			"fields": [{fieldName1}, {fieldName2}^{weight}...]
		}
	}
}
  • match_phrase 关键字,搜索内容的分词结果必须在文档分词中都包含,且顺序必须相同,而且必须连续(词与词之间必须紧贴在一起),除非设置了 slop 属性,允许词语之间跳过的文字数量
POST /{indexName}/_doc/_search
{
	"query": {
		"match_phrase": {
			"desc": {
				"query": {searchTxt},
				"slop": {slopNum}
			}
		}
	}
}
  • term 关键字与 terms 关键字,将 搜索内容作为一整个关键词去搜索,而不是进行分词后搜索,同时 terms 支持多个词语匹配检索
POST /{indexName}/_doc/_search
// term
{
	"query": {
		"term": {
			{fieldName2}: {searchTxt2},
		}
	}
}
// terms
{
	"query": {
		"terms": {
			{fieldName1}: [{searchTxt1}, {searchTxt2}...]
		}
	}
}
  • prefix 关键字,根据前缀去查询
POST /{indexName}/_doc/_search
{
	"query": {
		"prefix": {
			// {prefixTxt} 作为前缀
			{fieldName}: {prefixTxt},
		}
	}
}
  • fuzzy 关键字,在用户进行搜索时可能出现打错字的现象,搜索引擎会自动纠正,然后尝试匹配数据
POST /{indexName}/_doc/_search
{
	"query": {
		"fuzzy": {
			{fieldName}: {errorWord} 
		}
	}
}
  • ids 关键字,根据主键 ID 搜索
POST /{indexName}/_doc/_search
{
	"query": {
		"ids": {
			"type": "_doc",
			"values": [{id1}, {id2}...]
		}
	}
}

1.2 布尔查询

  • 布尔查询(多重组合查询
    • must:查询必须匹配搜索条件,类似于 SQL 语句的 and
    • should:查询匹配满足一个以上条件,类似于 SQL 语句的 or
    • must_not:不匹配搜索条件,一个都不要满足
    • 有时候,搜索同一个文档字段属性,希望 搜索内容分词A搜索内容分词B 权重更高可以使用 should 模式并设置 boost 权重属性
POST /{indexName}/_doc/_search
// 使用 must 举例
{
	"query": {
		"bool": {
			"must": [
				{
					"multi_match": {
						"query": {searchTxt1},
						"fields": [{fieldName1}, {fieldName2}..]
					}
				},
				{
					"term": {
						{fieldName3}: {searchTxt2}
					}
				},
				{
					"term": {
						{fieldName4}: {searchTxt3}
					}
				},
				...
				}
			]
		}
	}
}
// 同时使用 must,should,must_not 也是可以的
{
	"query": {
		"bool": {
			"must": [
				...
			]
			"should": [
				...
			]
			"must_not": [
				...
			]
		}
	}
}
// 使用 should 时,可以添加权重,举例
{
	"query": {
		"bool": {
			"should": [
				{
					"match": {
						"desc": {
							"query": "律师",
							"boost": 18
						}
					}
				},
				{
					"match": {
						"desc": {
							"query": "进修",
							"boost": 2
						}
					}
				}
			]
		}
	}
}

1.3 过滤器

对搜索出来的结果进行数据过滤(即查询后,对结果数据的筛选),不会到 ES 库里去搜,不会计算文档的相关度分数,所以过滤的性能会比较高,过滤器可以和全文搜索结合在一起使用。
post_filter 元素和上述的 query 元素一样,都是顶层元素,但 post_filter 不会计算数据的匹配度相关性分数,不会据分数排序。
举例:

POST /{indexName}/_doc/_search
// term
{
	"query": {
		"term": {
			{fieldName2}: {searchTxt2},
		}
	},
	// money 字段属性需要大于 60,小于 100
	"post_filter": {
		"range": {
			"money": {
				"gt": 60,
				"lt": 100
			}
		}
	}
}

1.4 排序

sort 元素和上述的 query 元素一样,都是顶层元素。

POST /{indexName}/_doc/_search
// term
{
	"query": {
		"term": {
			{fieldName2}: {searchTxt2},
		}
	},
	"sort": [
		{
			{fieldName1}: "desc"
		},
		{
			{fieldName2}: "asc"
		}
		...
	]
}

对文本排序,由于文本会被分词,所以排序的时候就会不知道用哪个分词后的内容去进行排序,所以需要在一开始设置文档字段的时候额外添加一个附属属性 keyword,用于排序:

POST /{indexName}/_mapping
{
  "properties": {
    {fieldName}: {
      "type": {typeName},
      "analyzer": {analyzerName},
      // 设置 keyword
      "fields": {
			"keyword": {
				"type": "keyword"
			}
		}
    }
  }
}

1.5 关键字高亮显示

POST /{indexName}/_doc/_search
// term
{
	"query": {
		"term": {
			{fieldName}: {searchTxt},
		},
		"term": {
			{fieldName2}: {searchTxt2},
		}
	},
	// 搜索词前后添加 span 标签
	"highlight": {
		"pre_tags": ["<span class="highlight">"],
		"post_tags": ["</span>"],
		"fields": {
			{fieldName}:{},
			{fieldName2}:{}
		}
	}
}

2 深度分页

深度分页其实就是指搜索的深浅度,比如第 10000 页,ES 在获取第 9999 条到 10009 条数据的时候,假如设置了多个主分片,那么它会从每个分片中拿出 10009 条数据集合在一起,再对这些汇总数据进行排序处理,最后获取对应的 10 数据,这样一来就会有性能的问题,ES 默认是不支持操作一万条数据以上的分页查询,而我们也应该避免深度分页操作(限制分页页数)
通过设置 index_max_result_window 来突破限制

PUT /{indexName}/_settings
{
	"index_max_result_window": "20000"
}

2.1 scroll 滚动搜索

一次性查询一万加的数据,往往会造成性能影响,因为数据量太多,这时候就可以使用滚动搜索。
滚动搜索可以先查询出一些数据,然后再接着依次往下查询,查询的时候会返回一个滚动 ID,相当于一个 锚标记,接下来的每次查询都需要携带上一次返回的 锚标记,值得注意的是,如果有数据变更,搜索出来的数据也只是旧版本的数据。
第一次滚动查询:

// scroll=1m 相当于是一个session会话时间,搜索保持上下文1分钟
POST /{indexName}/_search?scroll=1m
{
	"query": {
		"match_all": {}
	},
	"sort": ["_doc"],
	"size": 5 // 设置单页查询数量
}

后续查询:

POST /_search/scroll
{
	"scroll": "1m", //相当于是一个session会话时间,搜索保持上下文1分钟
	"scroll_id": {scroll_id}
}

3 批量操作

bulk 操作和以往的普通的请求格式有区别,它不能支持格式化 json,它的发送数据格式是:

{action:{metadata}}\n
{request body}\n
{action:{metadata}}\n
{request body}\n
...
  • {action:{metadata}} 代表批量操作的类型,不同操作类型之间是可以混合在同一请求中使用的
    • create:新增,如果文档不存在,就创建他,存在则会报错,但不影响其它操作
    • index:创建或替换一个现有的文档
    • update:部分更新文档
    • delete:删除一个文档
  • \n 即是回车符(不是填写 \n 进去请求体中,而是直接按回车键即可),每行结尾必须填写的规范(包括最后一行
  • {request body}:增和改操作的内容,删除操作无需携带

metadata 中需要指定要操作的文档的 _index(索引表表名)、_type(固定值为 _doc)和 _id,其中 _index_type 可以直接在 url 中指定

  • create 操作
POST /_bulk 
// 或者 /{indexName}/_doc/_bulk 这样指定url的话,下方 metaData 就无需声明 _index 和 _type 
{"create":{"_index":{indexName1},"_type":"_doc","_id":{id1}}}
{{fieldName1}: {value1}, {fieldName2}: {value2}}
{"create":{"_index":{indexName1},"_type":"_doc","_id":{id2}}}
{{fieldName1}: {value3}, {fieldName2}: {value4}}
{"create":{"_index":{indexName2},"_type":"_doc","_id":{id3}}}
{{fieldName3}: {value5}, {fieldName4}: {value6}}
  • index 操作,创建或替换一个现有的文档
POST /{indexName}/_doc/_bulk
{"index":{"_id":{id1}}}
{{fieldName1}: {value1}, {fieldName2}: {value2}}
{"index":{"_id":{id2}}}
{{fieldName1}: {value3}, {fieldName2}: {value4}}
  • update 操作,创建或替换一个现有的文档
POST /{indexName}/_doc/_bulk
{"update":{"_id":{id1}}}
{"doc":{{fieldName1}: {value1}, {fieldName2}: {value2}}}
{"index":{"_id":{id2}}}
{"doc":{{fieldName1}: {value3}, {fieldName2}: {value4}}}
  • delete 操作,创建或替换一个现有的文档
POST /{indexName}/_doc/_bulk
{"delete":{"_id":{id1}}}
{"delete":{"_id":{id2}}}

有关Elasticsearch入门笔记(DSL搜索)的更多相关文章

  1. ruby-on-rails - Nokogiri:使用 XPath 搜索 <div> - 2

    我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll

  2. ruby - 如何在 Ruby 中创建无类 DSL? - 2

    我正在尝试找出如何为我的Ruby项目创建一种“无类DSL”,类似于在Cucumber步骤定义文件中定义步骤定义或在Sinatra应用程序中定义路由。例如,我想要一个文件,其中调用了我的所有DSL函数:#sample.rbwhen_string_matches/hello(.+)/do|name|call_another_method(name)end我认为用我的项目特有的一堆方法污染全局(内核)命名空间是一种不好的做法。因此方法when_string_matches和call_another_method将在我的库中定义,并且sample.rb文件将以某种方式在我的DSL方法的上下文中

  3. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  4. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

  5. 【Java入门】使用Java实现文件夹的遍历 - 2

    遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg

  6. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  7. ruby - 如何搜索有用的 ruby - 2

    寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是ruby​​gems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和ruby​​gems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko

  8. ruby - 如何搜索、递增和替换 Ruby 字符串中的整数子字符串? - 2

    我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/

  9. ruby - Ruby 中的必应搜索 API - 2

    我读了"BingSearchAPI-QuickStart"但我不知道如何在Ruby中发出这个http请求(Weary)如何在Ruby中翻译“Stream_context_create()”?这是什么意思?"BingSearchAPI-QuickStart"我想使用RubySDK,但我发现那些已被弃用前(Rbing)https://github.com/mikedemers/rbing您知道Bing搜索API的最新包装器(仅限Web的结果)吗? 最佳答案 好吧,经过一个小时的挫折,我想出了一个办法来做到这一点。这段代码很糟糕,因为它是

  10. Ruby#index 方法 VS 二进制搜索 - 2

    给定一个元素和一个数组,Ruby#index方法返回元素在数组中的位置。我使用二进制搜索实现了我自己的索引方法,期望我的方法会优于内置方法。令我惊讶的是,内置的在实验中的运行速度大约是我的三倍。有Rubyist知道原因吗? 最佳答案 内置#indexisnotabinarysearch,这只是一个简单的迭代搜索。但是,它是用C而不是Ruby实现的,因此自然可以快几个数量级。 关于Ruby#index方法VS二进制搜索,我们在StackOverflow上找到一个类似的问题:

随机推荐