赞
踩
它可以将多个字段拼接成一个字段,这个字段不会存在于source中,但是可以用于搜索。
copy_to生成的单字段可以实现多字段的匹配搜索能力。
例如:POST users/_search
PUT users
{
“mappings”: {
“properties”: {
“firstName”:{
“type”: “text”,
“copy_to”: “fullName”
},
“lastName”:{
“type”: “text”,
“copy_to”: “fullName”
}
}
}
}
{
“query”: {
“match”: {
“fullName”:{
“query”: “Ruan Yiming”,
“operator”: “and”
}
}
}
}
这个例子中,我们想找到firstName=Ruan,lstName=Yiming的文档,使用了fullName进行单字段匹配+ “operator”: "and"可以实现。但是如果没有这个字段,就需要使用多字段实现了。
动态设定字段类型的模版,构建索引时可以指定。例如,以“is”开头的字段可以默认构建成boolean类型。注意match_mapping_type, 可以指定为string,但是es的字段mapping中的mapping是不可以设置成string类型的。
PUT my_index { "mappings": { "dynamic_templates": [ { "strings_as_boolean": { "match_mapping_type": "string", "match":"is*", "mapping": { "type": "boolean" } } } ] } }
当你向一个不存在的索引添加数据时,默认的字段映射是怎样的呢?
数值型识别会关闭,“111”会被识别成text类型, 111 会被识别成long类型
布尔型识别关闭,“ture”会被识别成text类型,ture会被识别成布尔类型
日期识别开启,“2019-01-01”会被识别成date类型
索引模版,帮助创建索引时默认设置setting和mapping中的一些属性。模板仅在一个索引被新创建时,才会产生作用。修改模板不会影响已创建的索引,你可以设定多个索引模板,这些设置会被“merge”在一起。你可以指定“oder”的数值,控制“merging”的过程
index Templte的工作流程
插入和更新
方式一:不指定create还是update。效果:有则替换,无则插入。底层实现,先删除,后写入
PUT users/_doc/1
{
"user" : "Jack",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
方式二:指定create或是update
#create document. 指定Id。如果id已经存在,报错
PUT users/_create/2
{
"user" : "Jack",
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
#字段存在则更新,字段不存在则插入新字段。
POST users/_update/1/
{
"doc":{
"post_date" : "2019-05-15T14:12:12",
"message" : "trying out Elasticsearch"
}
}
删除
#通过文档id删除
DELETE users/_doc/1
Bulk 操作
可以单批次执行多条,不同操作类型的指令,如下
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test2", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
mget批量获取
索引名称可以放在url中指定或者放在json中指定,甚至可以指定获取的source字段
#URI中指定index GET /test/_mget { "docs" : [ { "_id" : "1" }, { "_id" : "2" } ] } #指定获取的source字段 GET /_mget { "docs" : [ { "_index" : "test", "_id" : "1", "_source" : false }, { "_index" : "test", "_id" : "2", "_source" : ["field3", "field4"] }, { "_index" : "test", "_id" : "3", "_source" : { "include": ["user"], "exclude": ["user.location"] } } ] }
msearch操作
单批次查询多个索引数据
POST kibana_sample_data_ecommerce/_msearch
{}
{"query" : {"match_all" : {}},"size":1}
{"index" : "kibana_sample_data_flights"}
{"query" : {"match_all" : {}},"size":2}
查看不同的analyzer的效果
#standard,可用于英文,按单词分词,大写转小写,去除标点符号 GET _analyze { "analyzer": "standard", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #simpe,可用于英文,按单词分词,大写转小写,去除数字,标点符号 GET _analyze { "analyzer": "simple", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #stop,可用于英文,按单词分词,大写转小写,去除数字,冠词,标点符号 GET _analyze { "analyzer": "stop", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #whitespace,可用于英文,按空格分词。无其他过滤。 GET _analyze { "analyzer": "whitespace", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #keyword,不分词 GET _analyze { "analyzer": "keyword", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #pattern,可用于英文,按单词分词,大写转小写,去除标点符号 GET _analyze { "analyzer": "pattern", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #english,可用于英文,按单词分词,大写转小写,去除标点符号,词性转化 GET _analyze { "analyzer": "english", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." } #icu_analyzer,用于中文分词 POST _analyze { "analyzer": "icu_analyzer", "text": "他说的确实在理”" } #standard,可用于中文分词,按单个中文汉字分词 POST _analyze { "analyzer": "standard", "text": "他说的确实在理”" }
GET test2/_termvectors/2?fields=test_text 返回字段分词后的统计信息
基于 Term 的查询
● Term 的重要性
● Term 是表达语意的最⼩小单位。搜索和利利⽤用统计语⾔言模型进⾏行行⾃自然语⾔言处理理都需要处理理 Term
● 特点
● Term Level Query: Term Query / Range Query / Exists Query / Prefix Query /Wildcard Query
● 在 ES 中,Term 查询,对输⼊入不不做分词。会将输⼊入作为⼀一个整体,在倒排索引中查找准确的词项,并 且使⽤用相关度算分公式为每个包含该词项的⽂文档进⾏行行相关度算分 – 例例如“Apple Store”
● 可以通过 Constant Score 将查询转换成⼀一个 Filtering,避免算分,并利利⽤用缓存,提⾼高性能
可以压测下这两个请求方式对性的开销。
PUT articles { "mappings": { "properties": { "title_completion":{ "type": "completion" } } } } POST articles/_bulk { "index" : { } } { "title_completion": "lucene is very cool"} { "index" : { } } { "title_completion": "Elasticsearch builds on top of lucene"} { "index" : { } } { "title_completion": "Elasticsearch rocks"} { "index" : { } } { "title_completion": "elastic is the company behind ELK stack"} { "index" : { } } { "title_completion": "Elk stack rocks"} { "index" : {} } POST articles/_search?pretty { "size": 0, "suggest": { "article-suggester": { "prefix": "elk ", "completion": { "field": "title_completion" } } } }
elasticsearch 提供的联想词能力
3种Suggestion Mode
Missing – 如索引中已经存在,就不提供建议
Popular – 推荐出现频率更加⾼的词
Always – ⽆论是否存在,都提供建议
should和must放在同一层级时,并不要求should中的内容一定要被匹配到,只是匹配中的话,相关性的得分会更高。
可以加一个"minimum_should_match": n,来控制必须匹配中的should条件的个数。
如果bool中只用should集合没有must集合,那么必须满足should
#改变数据模型,增加字段。解决数组包含而不是精确匹配的问题 POST /newmovies/_bulk { "index": { "_id": 1 }} { "title" : "Father of the Bridge Part II","year":1995, "genre":"Comedy","genre_count":1 } { "index": { "_id": 2 }} { "title" : "Dave","year":1993,"genre":["Comedy","Romance"],"genre_count":2 } #must,有算分 POST /newmovies/_search { "query": { "bool": { "must": [ {"term": {"genre.keyword": {"value": "Comedy"}}}, {"term": {"genre_count": {"value": 1}}} ] } } }
#嵌套,实现了 should not 逻辑 POST /products/_search { "query": { "bool": { "must": { "term": { "price": "30" } }, "should": [ { "bool": { "must_not": { "term": { "avaliable": "false" } } } } ], "minimum_should_match": 1 } } }
权重提升值,影响算分
POST blogs/_search { "query": { "bool": { "should": [ {"match": { "title": { "query": "apple,ipad", "boost": 1.1 } }}, {"match": { "content": { "query": "apple,ipad", "boost": 1 } }} ] } } }
boosting 中可以控制匹配中的关键字是正向的算分还是逆向的算分。
POST news/_search
{
“query”: {
“boosting”: {
“positive”: {
“match”: {
“content”: “apple”
}
},
“negative”: {
“match”: {
“content”: “pie”
}
},
“negative_boost”: 0.5
}
}
}
terms查询接的是一个数组,文档中的字段只要匹配中一个就算匹配成功
需要使用bool查询
POST products/_search { "query": { "constant_score": { "filter": { "bool": { "must" : [ {"range":{ "price":{ "gte":10 } } }, {"range":{ "date":{ "gte":"2018-01-01" } } } ] } }, "boost": 1.2 } } }
使用评分最高的字段评分作为文档匹配的总评分,不会对查询搜索字段的评分进行加和。
POST /blogs/_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "Brown fox" }},
{ "match": { "body": "Brown fox" }}
]
}
}
}
但是这样一刀切的做法也不对,评分低的字段虽然不能和评分高的字段一样的权重,但是也不能完全没有权重。tie_breaker可以给评分较低的字段一个权重。
POST blogs/_search
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Quick pets" }},
{ "match": { "body": "Quick pets" }}
],
"tie_breaker": 0.2
}
}
}
multi_match 查询为能在多个字段上反复执行相同查询提供了一种便捷方式。
multi_match 多匹配查询的类型有多种,其中的三种恰巧与 了解我们的数据 中介绍的三个场景对应,即: best_fields 、 most_fields 和 cross_fields (最佳字段、多数字段、跨字段)。
当对英文单词进行词性还原的时候,比如去ing(动词的进行时还原成原型),去s(复数还原成单数),单词的长度会变短,召回率会提升。所以可以通过给字段添加子字段,并且字字段的分词器选择english的方式。查询时使用mutilMatch匹配父字段和子字段进行匹配查询。
PUT /my_index { "mappings": { "properties": { "title": { "type": "text", "fields": { "english": { "type": "text", "analyzer": "english" } } } } } } GET my_index/_mapping PUT /my_index/_doc/1 { "title": "I'm happy for this foxes" } PUT /my_index/_doc/2 { "title": "I'm not happy about my fox problem" } DELETE /my_index/_doc/1 GET /_search { "query": { "multi_match": { "type": "most_fields", "query": "foxes", "fields": [ "title" ] } } }
https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-using.html#script-stored-scripts
可以再总结下 项目中使用到脚本删除的场景
脚本更新操作实践:
https://www.jianshu.com/p/678c452a0398
什么是painless?
painless语言是一种类似Java的脚本语言。有多类似呢?写脚本代码时,就当是在写Java就好了,基本可以随心所欲地使用JDK中的API。所以ES的脚本编写可以说是非常轻松和简单,并不需要去学一门新的脚本语言(比如Lua).
为什么要使用脚本更新,相对于非脚本的方式它具备哪些优点
通过使用更新脚本,我们就可以将两步的读取-更新操作,合并成一次的更新脚本。如果善加利用脚本中的Upsert功能,我们甚至可以将插入-读取-更新,三步的操作合并成一次Update调用。使用脚本自然而然地解决了我们刚刚提出的第一个问题,大幅地减轻了多次往返所造成的大量开销。同时即使ES中出现了巨型文档,也不会直接对应用集群的性能造成影响。
而面对竞争问题,仅仅使用脚本更新并不能解决race condition的问题,因为在ES内部并没有对脚本的执行进行同步。即使脚本内部看上去是原子性的,实际上仍然可能将脚本更新到一个旧版本的文档上。然而,即使如此,合并成一次的Update操作也大大简化了同步问题的复杂性,我们只需要给Update操作带上版本号,利用乐观的版本控制,就可以轻松地保证脚本不执行在中间状态中。而且在高度竞争的环境下,Update脚本本身的体量也非常小,也避免了大量重试带来的性能开销和程序复杂度。
当然,ES脚本也并不是没有缺点的。类似SQL中逐渐被废弃的存储过程,ES脚本也有着很多存储过程所具有的问题。比如脚本更新非常难以调试,因为代码被写到了请求代码中,就很难以对脚本本身进行完备的测试。脚本代码的可读性往往也比直接的应用代码要差一些。另外,使用脚本会将很多计算逻辑从应用集群转移到ES集群,虽然节省了很多IO开销,但很有可能会增加ES的CPU负担,这点需要大量的实践测试,才能真正放心使用。而且在使用stored型脚本时,会给ES集群增加一个脚本ID的状态,在迁移数据、重建集群时,一定要记得迁移这个新增的状态量,否则所有使用该脚本的操作都会失效。最后,使用ES独有的脚本功能也给数据迁移到其他数据库带来了难度,使用应用和ES更加高度耦合,不过这一点其实不必过度考虑,使用ES时设计的数据模型,本就应该和其他数据库有所不同。\
PUT movies-2019/_doc/1 { "name":"the matrix", "rating":5 } PUT movies-2019/_doc/2 { "name":"Speed", "rating":3 } POST _aliases { "actions": [ { "add": { "index": "movies-2019", "alias": "movies-latest" } } ] } POST movies-latest/_search { "query": { "match_all": {} } } POST _aliases { "actions": [ { "add": { "index": "movies-2019", "alias": "movies-lastest-highrate", "filter": { "range": { "rating": { "gte": 4 } } } } } ] } POST movies-lastest-highrate/_search { "query": { "match_all": {} } }
原理:会生成一个快照供查询的时候使用,注意有新的数据写入后无法被查询到。
使用案例:/index/_search/scroll=5m 就表示使用了scrollAPI功能,调用后会返回一个scroll_id, 用于下次的查询。并且下次查询的时候还需带上一次续期时间scroll。
参考:https://www.cnblogs.com/wangzhuxing/p/9569727.html#_label0_0
#Scroll API DELETE users POST users/_doc {"name":"user1","age":10} POST users/_doc {"name":"user2","age":20} POST users/_doc {"name":"user3","age":30} POST users/_doc {"name":"user4","age":40} POST /users/_search?scroll=5m { "size": 1, "query": { "match_all" : { } } } POST users/_doc {"name":"user5","age":50} POST /_search/scroll { "scroll" : "1m", "scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFlk2Q3FISVhwUXEtc2FYa242Z3BQSlEAAAAAAAACcxZ2WFVGMzlvR1F2V0NWRkMtRDkzdGJ3" }
默认的sort查询就是可以使用的searchAfter能力的,将上次返回的额sort值放在search_after参数中。
api使用的方式如下:
POST users/_search { "size": 1, "query": { "match_all": {} }, "sort": [ {"age": "desc"} , {"_id": "asc"} ] } POST users/_search { "size": 1, "query": { "match_all": {} }, "search_after": [ 10, "ZQ0vYGsBrR8X3IP75QqX"], "sort": [ {"age": "desc"} , {"_id": "asc"} ] }
https://www.elastic.co/guide/en/elasticsearch/reference/7.1/tune-for-search-speed.html
直观的说,Nested实际上就是Object的数组。如下,这个user就是个nested结构
{
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
Object虽然是个对象,但是实际存储时是在当前文档里打平存储的。如上那个例子,如果只有一个user,那么在真实索引中实际上是下面这样的
{
"user.first" : "John",
"user.last" : "Smith"
}
而如果是个list,那么就成了
{
"user.first" : ["John","Alice"],
"user.last" : ["Smith","White"]
}
https://czjxy881.github.io/elasticsearch/%E4%B8%80%E8%B5%B7%E6%9D%A5%E5%AD%A6ES-%E6%B5%85%E8%B0%88Nested%E7%BB%93%E6%9E%84/
可以用与跨字段检索,具体用例如下
https://cloud.tencent.com/developer/article/1697284
https://blog.csdn.net/HuoqilinHeiqiji/article/details/103460430
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。