jjzjj

Elasticsearch高级查询Query DSL

Charge8 2024-04-09 原文

一、高级查询Query DSL简介

1、Query DSL(简介

Elasticsearch中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL(Domain Specified Language) 。

Query DSL是利用 Rest API传递 JSON格式的请求体(RequestBody)数据与 ES进行交互,这种方式的丰富查询语法让 ES检索变得更强大,更简洁。

基本语法:

GET /es_db/_doc/_search {json请求体数据} 
#可以简化为下面写法 
GET /es_db/_search {json请求体数据} 

官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl.html

2、测试数据

示例数据:

#创建索引,并指定ik分词器 
PUT /db_idx4
{
    "settings":{
        "index":{
            "analysis.analyzer.default.type":"ik_max_word"
        }
    }
}
# 批量创建文档
POST _bulk
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":1}}
{"id":1,"name":"赵子龙","sex":1,"age":18, "address":"三国演义常山赵子龙", "desc":"刘备大将之一"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":2}}
{"id":2,"name":"赵云","sex":1,"age":19, "address":"王者打野刺客赵云", "desc":"王者刺客"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":3}}
{"id":3,"name":"关云长","sex":1,"age":23, "address":"三国演义关云长", "desc":"桃园结义刘备二弟"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":4}}
{"id":4,"name":"关羽","sex":1,"age":23, "address":"王者边路", "desc":"可辅可边"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":5}}
{"id":5,"name":"张益德","sex":1,"age":22, "address":"三国演义张益德", "desc":"桃园结义刘备三弟"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":6}}
{"id":6,"name":"张飞","sex":1,"age":22, "address":"王者辅助", "desc":"王者辅助"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":7}}
{"id":7,"name":"张玄德","sex":1,"age":25, "address":"三国演义张玄德", "desc":"桃园结义刘皇叔"} 
{"index":{"_index":"db_idx4", "_type":"_doc", "_id":8}}
{"id":8,"name":"小乔","sex":0,"age":18, "address":"三国演义小乔", "desc":"周瑜之妻"}

二、查询操作

1、查询所有match_all

使用 match_all,默认只会返回 10条数据。

原因:_search查询默认采用的是分页查询,每页记录数 size的默认值为 10。如果想显示更多数据,指定 size 。

#使用 match_all,默认只会返回 10条数据。
GET /db_idx4/_search 
#等同于 
GET /db_idx4/_search 
{
    "query":{
        "match_all":{

        }
    }
}

1.1 指定条数size

size 关键字:指定查询结果中返回指定条数。 默认返回值10条。

# 指定 size 
GET /db_idx4/_search 
{
    "query":{
        "match_all":{

        }
    },
    "from":1,
    "size":3
}

1.2 分页查询form

from 关键字:用来指定起始返回位置,和size关键字连用可实现分页效果

GET /db_idx4/_search 
{
    "query":{
        "match_all":{

        }
    },
    "from":2,
    "size":200
}

如果 size = 30000,,就会出现异常。

  • 查询结果的窗口太大,from + size的结果必须小于或等于10000。
  • 查询结果的窗口的限制可以通过参数 index.max_result_window进行设置。
  • 也可以采用 scroll api更高效的请求大量数据集。
#修改现有某个的索引
PUT /db_idx4/_settings 
{
    "index.max_result_window":"20000"
}

2、深分页查询Scroll

改动 index.max_result_window参数值的大小,只能解决一时的问题,当索引的数据量持续增长时,在查询全量数据时还是会出现问题。而且会增加 ES服务器内存大结果集消耗完的风险。

最佳实践还是根据异常提示中的采用 scroll api更高效的请求大量数据集。

GET /db_idx4/_search?scroll=1m
{
    "query":{
        "match_all":{

        }
    },
    "size":2
}

查询结果: 除了返回前2条记录,还返回了一个游标ID值_scroll_id

2.1 采用游标id查询:

# scroll_id 的值就是上一个请求中返回的 _scroll_id 的值 
GET /_search/scroll 
{
    "scroll":"1m",
    "scroll_id":"FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmNpTWtscHBSUnVxYmM0ZEtrc1hGMGcAAAAAAAA1ABZlYko0RmdtUlNUT0ItcUo2TDNMbjdn"
}

多次根据 scroll_id游标查询,直到没有数据返回则结束查询。采用游标查询索引全量数据, 更安全高效,限制了单次对内存的消耗。

3、指定字段排序sort

注意:会让得分失效。

GET /db_idx4/_search
{
    "query":{
        "match_all":{

        }
    },
    "sort":[
        {
            "age":"desc"
        }
    ]
}

4、_source返回指定字段

_source 关键字:是一个数组,在数组中用来指定展示那些字段。

GET /db_idx4/_search
{
  "query": {
    "match_all": {}
  },
  "_source": ["name","address"]
}

5、match 查找

match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找

match支持下面几个参数:

  • query:指定匹配的值
  • operator:匹配条件类型
  • and:条件分词后都要匹配
  • or:条件分词后有一个匹配即可(默认)
  • minmum_should_match :最低匹配度,即条件在倒排索引中最低的匹配度
#模糊匹配 match 分词后or的效果 
GET /db_idx4/_search
{
  "query": {
    "match": {
      "address": "王者打野"
    }
  }
}

#分词后 and的效果 
GET /db_idx4/_search
{
  "query": {
    "match": {
      "address": {
        "query": "王者打野",
        "operator": "and"
      }
    }
  }
}

当 operator参数设置为 or时,minnum_should_match参数用来控制匹配的分词的最少数量。

#最少匹配打野,刺客两个词 
GET /db_idx4/_search
{
  "query": {
    "match": {
      "address": {
        "query": "刺客打野",
        "operator": "or",
        "minimum_should_match": 2
      }
    }
  }
}

6、多字段查询multi_match

multi_match 关键字:可以根据字段类型,决定是否使用分词查询,得分最高的在前面。

GET /db_idx4/_search
{
  "query":{
    "multi_match": {
      "query": "王者打野",
      "fields": ["address", "desc"]
    }
  }
}

注意:字段类型分词,将查询条件分词之后进行查询,如果该字段不分词就会将查询条件作为整体进行查询。

7、query_string 查询

允许我们在单个查询字符串中指定 AND | OR | NOT条件,同时也和 multi_match query 一样,支持多字段搜索。和match类似,但是 match需要指定字段名,query_string是在所有字段中搜索,范围更广泛。

注意:查询字段分词就将查询条件分词查询,查询字段不分词将查询条件不分词查询。

#未指定字段查询 
GET /db_idx4/_search
{
  "query":{
    "query_string": {
      "query": "赵云 OR 赵子龙"
    }
  }
}

#指定单个字段查询 
GET /db_idx4/_search
{
  "query":{
    "query_string": {
      "default_field": "address", 
      "query": "赵云 OR 赵子龙"
    }
  }
}

#指定多个字段查询 
GET /db_idx4/_search
{
  "query":{
    "query_string": {
      "fields": ["address","name"], 
      "query": "赵云 OR 赵子龙 OR 张飞"
    }
  }
}

8、simple_query_string 查询语法

类似Query String,但是会忽略错误的语法,同时只支持部分查询语法,不支持AND OR NOT,会当作字符串处理。

支持部分逻辑:

  • “+” 替代AND
  • “|” 替代OR
  • “-” 替代NOT
#simple_query_string 默认的operator是OR 
GET /db_idx4/_search 
{
  "query":{
    "simple_query_string": {
      "query": "王者打野",
      "fields": ["address","desc"], 
      "default_operator": "OR"
    }
  }
}

GET /db_idx4/_search 
{
  "query":{
    "simple_query_string": {
      "query": "王者+打野",
      "fields": ["address","desc"]
    }
  }
}

9、关键词查询Term

Term用来使用关键词查询(精确匹配),还可以用来查询没有被进行分词的数据类型。

  • term是表达语意的最小单位,搜索和利用统计语言模型进行自然语言处理都需要处理Term。
  • match在匹配时会对所查找的关键词进行分词,然后按分词匹配查找,而 term会直接对关键词进行查找。

一般模糊查找的时候,多用 match,而精确查找时可以使用 term。

在 ES中默认使用分词器为标准分词器(Standard Analyzer)标准分词器对于英文单词分词,对于中文单字分词。

在 ES的 Mapping Type 中 keyword,date,integer,long,double,boolean or ip 这些类型不分词,只有 text类型分词。

GET /db_idx4/_search
{
  "query": {
    "term": {
          "address.keyword": "三国演义小乔"
        }
  }
}

可以通过 Constant Score 将查询转换成一个 Filtering,避免算分,并利用缓存,提高性能。

GET /db_idx4/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "address.keyword": "三国演义小乔"
        }
      }
    }
  }
}

对bool,日期,数字,结构化的文本可以利用 term做精确匹配。

GET /db_idx4/_search
{
  "query": {
    "term": {
      "age": {
        "value": 18
      }
    }
  }
}

10、范围查询range

range:范围关键字:

  • gte 大于等于
  • lte 小于等于
  • gt 大于
  • lt 小于
  • now 当前时间
POST /db_idx4/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 18,
        "lte": 20
      }
    }
  }
} 

11、日期range

DELETE /product 
POST /product/_bulk 
{"index":{"_id":1}} 
{"price":100,"date":"2022‐01‐01","productId":"XHDK‐1293"} 
{"index":{"_id":2}} 
{"price":200,"date":"2022‐02‐01","productId":"KDKE‐5421"} 

GET /product/_mapping 

GET /product/_search
{
  "query": {
    "range": {
      "date": {
        "lte": "now‐2y"
      }
    }
  }
}

12、多id查询ids

ids 关键字 :值为数组类型,用来根据一组id获取多个对应的文档。

GET /db_idx4/_search
{
  "query": {
    "ids": {
      "values": [
        1,
        2
      ]
    }
  }
} 

13、高亮highlight

highlight 关键字:可以让符合条件的文档中的关键词高亮。

highlight相关属性:

  • pre_tags 前缀标签
  • post_tags 后缀标签
  • tags_schema 设置为 styled可以使用内置高亮样式
  • require_field_match 多字段高亮需要设置为false
GET /db_idx4/_search
{
  "query": {
    "term": {
      "address": {
        "value": "王者"
      }
    }
  },
  "highlight": {
    "fields": {
      "*": {}
    }
  }
}

13.1 自定义高亮html标签

可以在highlight中使用 pre_tags和 post_tags。

GET /db_idx4/_search
{
  "query": {
    "term": {
      "address": {
        "value": "王者"
      }
    }
  },
  "highlight": {
    "post_tags": [
      "</span>"
    ],
    "pre_tags": [
      "<span style='color:red'>"
    ],
    "fields": {
      "*": {}
    }
  }
} 

13.2 多字段高亮

GET /db_idx4/_search
{
  "query": {
    "term": {
      "address": {
        "value": "王者"
      }
    }
  },
  "highlight": {
    "pre_tags": [
      "<font color='red'>"
    ],
    "post_tags": [
      "<font/>"
    ],
    "require_field_match": "false",
    "fields": {
      "address": {},
      "desc": {}
    }
  }
} 

更多使用可查看官方文档。

– 求知若饥,虚心若愚。

有关Elasticsearch高级查询Query DSL的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  3. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

  4. ruby-on-rails - solr 清理查询 - 2

    我在Rails上使用带有ruby​​的solr。一切正常,我只需要知道是否有任何现有代码来清理用户输入,比如以?开头的查询。或* 最佳答案 我不知道执行此操作的任何代码,但理论上可以通过查看parsingcodeinLucene来完成并搜索thrownewParseException(只有16个匹配!)。在实践中,我认为您最好只捕获代码中的任何solr异常并显示“无效查询”消息或类似信息。编辑:这里有几个“sanitizer”:http://pivotallabs.com/users/zach/blog/articles/937-s

  5. ruby-on-rails - Rails 3 在一个查询中包含多个表 - 2

    我正在为锦标赛开发一个Rails应用程序。我在这个查询中使用了三个模型:classPlayertruehas_and_belongs_to_many:tournamentsclassTournament:destroyclassPlayerMatch"Player",:foreign_key=>"player_one"belongs_to:player_two,:class_name=>"Player",:foreign_key=>"player_two"在tournaments_controller的显示操作中,我调用以下查询:Tournament.where(:id=>params

  6. ruby-on-rails - Sunspot:如何对具有不同值的多个字段进行全文查询? - 2

    我想用sunspot重现以下原始solr查询q=exact_term_text:fooORterm_textv:foo*ORalternate_text:bar*但我无法通过标准的太阳黑子界面理解这是否可能以及如何实现,因为看起来:fulltext方法似乎不接受多个文本/搜索字段参数我不知道将什么参数作为第一个参数传递给fulltext,就好像我通过了"foo"或"bar"结果不匹配如果我传递一个空参数,我得到一个q=*:*范围过滤器(例如with(:term).starting_with('foo*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

  7. ruby-on-rails - 在不重新查询数据库的情况下重新排序 Rails 中的事件记录? - 2

    例如,假设我有一个名为Products的模型,并且在ProductsController中,我有以下代码用于product_listView以显示已排序的产品。@products=Product.order(params[:order_by])让我们想象一下,在product_listView中,用户可以使用下拉菜单按价格、评级、重量等进行排序。数据库中的产品不会经常更改。我很难理解的是,每次用户选择新的order_by过滤器时,rails是否必须查询,或者rails是否能够以某种方式缓存事件记录以在服务器端重新排序?有没有一种方法可以编写它,以便在用户排序时rails不会重新查询结果

  8. ruby-on-rails - 带句点(或句号)的 Rails 查询字符串。 - 2

    我目前正在尝试了解RoR。我将两个字符串传递到我的Controller中。一个是随机的十六进制字符串,另一个是电子邮件。该项目用于对数据库进行简单的电子邮件验证。我遇到的问题是当我输入如下内容来测试我的页面时:http://signup.testsite.local/confirm/da2fdbb49cf32c6848b0aba0f80fb78c/bob.villa@gmailcom我在:email的参数散列中得到的全部是'bob'。我在gmail和com之间留下了.,因为那样会导致匹配根本不起作用。我的路由匹配如下:match"confirm/:code/:email"=>"conf

  9. ruby - Rails Elasticsearch 聚合 - 2

    不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a

  10. ruby - 如何将编码的查询值添加到 URL? - 2

    我正在寻找一种方便实用的方法来将编码值添加到Ruby中的URL查询字符串。目前,我有:require'open-uri'u=URI::HTTP.new("http",nil,"mydomain.example",nil,nil,"/tv",nil,"show="+URI::encode("Rosie&Jim"),nil)pu.to_s#=>"http://mydomain.example/tv?show=Rosie%20&%20Jim"这不是我要找的,因为我需要得到“http://mydomain.example/tv?show=Rosie%20%26%20Jim”,这样show=值就

随机推荐