草庐IT

ES-DSL查询

许喜朝 2024-03-15 原文

DSL查询

DSL查询分类

查询所有:查询出所有数据(match_all)

全文检索:利用分词器对用户输入内容分词,然后去倒排索引库中匹配

  • match_query
  • multi_match_query

精确查询:根据精确词条值查找数据,一般是查找keyword,数值,boolean等字段

  • ids
  • range
  • Term

地理查询:根据经纬度查询

  • Geo_distance
  • Get_bounding_box

复合查询:复合查询可以将上述各种查询条件组合起来,合并查询条件

  • boool
  • function_score

DSL Query基本语法

GET /indexName/_search
{
  "query": {
    "查询类型": {
      "查询条件": "条件值"
    }
  }
}

全文检索查询

match查询:全文检索的一种,会对用户输入的内容分词,然后去倒排索引库检索

GET /indexName/_search
{
  "query": {
    "match": {
      "FIELD": "TEXT"
    }
  }
}

multi_match:与match查询类似,只不过允许同时查询多个字段

GET /indexName/_search
{
  "query": {
    "multi_match": {
      "query": "TEXT",
      "fields": ["FIELD1", " FIELD12"]
    }
  }
}

match与multi_match的区别

  • match根据一个条件查询
  • Multi_match根据多个字段查询,参与查询字段越多,查询性能越差,多字段建议使用all的方式

精确查询

精确查询一般是查找keyword、数值、日期、boolean等类型字段,所以不会对搜索条件分词,常见的有:

  • term:根据词条精确值查询
  • range:根据值的范围查询

trem查询语法:

// term查询
GET /indexName/_search
{
  "query": {
    "term": {
      "FIELD": {
        "value": "VALUE"
      }
    }
  }
}

range查询语法:

// range查询
GET /indexName/_search
{
  "query": {
    "range": {
      "FIELD": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

地理查询

根据经纬度查询

  • geo_bounding_box:查询geo_point值落在某个矩形范围的所有数据

语法:

// geo_bounding_box查询
GET /indexName/_search
{
  "query": {
    "geo_bounding_box": {
      "FIELD": {
        //左上角
        "top_left": {
          "lat": 31.1,
          "lon": 121.5
        },
        //右下角
        "bottom_right": {
          "lat": 30.9,
          "lon": 121.7
        }
      }
    }
  }
}

  • geo_distance:查询到指定中心点小于某个距离值的所有文档

语法:

// geo_distance 查询
GET /indexName/_search
{
  "query": {
    "geo_distance": {
      "distance": "距离",
      "FIELD": "经纬度坐标"
    }
  }
}

复合查询

复合查询:可以将其他简单查询组合起来,实现更复杂的搜索逻辑

相关性算分

当我们利用match查询文档时文档结果会根据于搜索词条的关联度打分,返回结果时按照分值进行排列

使用function score query,可以修改文档的相关性算分,根据新的到的算分排序

语法:

#相关性算分
GET /hotel/_search
{
  "query": {
    "function_score": {
      //原始查询条件
      "query": {
        "match": {
          "name": "外滩"
        }
      },
      "functions": [
        {
          //过滤条件
          "filter": {
            "term": {
              "city": "如家"
            }
          },
          //算分函数
          "weight": 10
        }
      ],
      //加权模式
      "boost_mode": "multiply"
    }
  }
}

语法解释:

  • query:原始查询条件,搜索文档并根据相关性打分

    functions:

    • ​ filter:过滤条件,复合条件的文档才会被重新算分
    • ​ 算分函数:将来会与query score运算,符合条件的文档才会被重新算分
      • ​ weight:给一个常量值,作为函数结果
      • ​ field_value_factor:用文档中的某个字段值作为函数结果
      • ​ random_scope:随机生成一个值,作为函数结果
      • ​ script_scope:自定义计算公式,公式结果作为函数结果
    • ​ 加权模式:
      • ​ multiply:两者相乘(默认)
      • ​ replace:用function score替换query score
      • ​ 其他:sum、avg、max、min

布尔查询

布尔查询是一个或者多个查询子句的组合

  • must:必须匹配每个子查询,类似“与”,
  • should:选择性匹配子查询,类似“或”,
  • must_not:必须不匹配,类似“非”不参与算分
  • fiter:必须不匹配,不参与算分

需求:搜索名字包含如家,价格不高于400在坐标31.21,121.5周围10km范围的酒店文档

语法:

#布尔查询
GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "如家"
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "price": {
              "gt": 400
            }
          }
        }
      ],
      "filter": [
        {
          "geo_distance": {
            "distance": "10km",
            "location": "31.21,121.51"
          }
        }
      ]
    }
  }
}

搜索结果处理

排序

es支持对搜索结果排序,默认是根据相关度算分来排序,可以排序的字段有:keyword类型、数值类型、地理坐标、日期类型等

通过评分和价格排序:

#通过评分和价格排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "score": {
        "order": "desc"
      },
      "price": {
        "order": "asc"
      }
    }
  ]
}

当有多个排序条件时会优先执行前面的条件

通过距离排序

#通过距离排序
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "_geo_distance": {
        "location": "31.226215,121.495706",
        "order": "asc",
        "unit": "km"
      }
    }
  ]
}

注意这里的经纬度是纬度在前

分页

es中默认只返回top10的数据,而如果要查询更多数据就需要修改分页参数了

es中通过修改from、size参数来控制返回的分页结果

#分页
GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  //起始记录数
  "from": 0,
  //获取文档总数
  "size": 20
}

语法解释:

from:获取文档的起始位置默认是0(from = size*(page-1))

size:一次获取的文档总数

注意:es能获取到的最大数据为10000

深度分页问题

es的分页原理是先查询出分页所需的所有文档(例如from=100,size=10,就会查询出110条数据再返回101-110的数据)当然这在单机状态是没有问题的,在分布式系统中就会出现问题

集群es中的数据是分片存储在不同的es机器上的,假如集群中有100台机器查询数据为from=990,size=10,es就会从不同的es机器上分别查找1000条数据,然后聚合重排序后返回991-1000的数据,这次查询就会查询出100*(990+10)=100000,这10万条数据放进内存重排序时非常消耗cpu和内存甚至造成服务器宕机,所以在业务中应尽量避免使用深度分页(es设定结果集的上限为10000)

深度分页问题解决方案

针对深度分页,es提供了两种解决方案

search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据(官方推荐方式)

scroll:原理将排序数据形成快照,保存在内存(不推荐使用)

搜索结果高亮

es支持给搜索出来的关键字加标签,前端在给相应标签写样式就实现了搜索功能高亮

语法:

#高亮显示
GET /hotel/_search
{
  "query": {
    "match": {
      "all": "如家"
    }
  },
  "highlight": {
    //开始标签
    "pre_tags": "<em>",
    //结束标签
    "post_tags": "</em>", 
    //是否字段匹配,默认情况下搜索字段需要与高亮字段匹配
    "require_field_match": "false", 
    //高亮字段
    "fields": {
      "name": {},
      "brand": {}
    }
  }
}

有关ES-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. 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方法的上下文中

  4. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  5. 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

  6. 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中提取小时

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

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

  8. 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

  9. 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*')(顾名思义)作为过滤器查询应用,因此不参与评分。似乎可以手动编写字符串(或者可能使

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

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

随机推荐