• 袁庭新ES系列12节 | Elasticsearch高级查询操作


    前言

    上篇文章讲了关于Elasticsearch的基本查询操作。接下来袁老师为大家带来Elasticsearch高级查询部分相关的内容。Elasticsearch是基于JSON提供完整的查询DSL(Domain Specific Language:领域特定语言)来定义查询。因此,我们有必要在专题模块来详细探讨Elasticsearch高级查询部分内容。

    我们先来做个热身,了解下这一小节学习的目标,我将带领大家从以下五个模块来学习Elasticsearch的高级查询相关技术。

    • 结果过滤查询
    • 条件过滤查询
    • 结果排序
    • 分页查询
    • 高亮显示

    一. 结果过滤查询

    默认情况下,Elasticsearch在搜索的结果中,会把文档中保存在_source的所有字段都返回。

    如果我们只想获取其中的部分字段,我们可以添加_source属性来进行过滤。

    1.直接指定字段

    演示示例:

    1. GET /yx/_search
    2. {
    3. "_source": ["title", "price"],
    4. "query": {
    5. "term": {
    6. "price": 2699
    7. }
    8. }
    9. }

    语法说明:在查询结构中,通过_source属性来指定查询结果集中需要保留哪些字段信息。

    响应结果:

    1. {
    2. "took": 90,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 1,
    12. "max_score": 1,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "lNC7KYUB35ub5htYEZMU",
    18. "_score": 1,
    19. "_source": {
    20. "price": 2699,
    21. "title": "小米手机"
    22. }
    23. }
    24. ]
    25. }
    26. }

    运行上述代码响应结果见下:

    2.指定includes和excludes

    我们也可以通过:

    属性

    描述

    includes

    来指定想要显示的字段

    excludes

    来指定不想要显示的字段

    注意:二者都是可选的。

    演示示例:

    1. GET /yx/_search
    2. {
    3. "_source": {
    4. "includes": ["title", "images"]
    5. },
    6. "query": {
    7. "term": {
    8. "price": 2699
    9. }
    10. }
    11. }

    响应结果:

    1. {
    2. "took": 148,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 1,
    12. "max_score": 1,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "lNC7KYUB35ub5htYEZMU",
    18. "_score": 1,
    19. "_source": {
    20. "images": "http://image.yx.com/12479122.jpg",
    21. "title": "小米手机"
    22. }
    23. }
    24. ]
    25. }
    26. }

    运行上述代码响应结果见下:

    下面的示例与上面的结果将是一样的:

    1. GET /yx/_search
    2. {
    3. "_source": {
    4. "excludes": ["price"]
    5. },
    6. "query": {
    7. "term": {
    8. "price": 2699
    9. }
    10. }
    11. }

    响应结果:

    1. {
    2. "took": 6,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 1,
    12. "max_score": 1,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "lNC7KYUB35ub5htYEZMU",
    18. "_score": 1,
    19. "_source": {
    20. "images": "http://image.yx.com/12479122.jpg",
    21. "title": "小米手机"
    22. }
    23. }
    24. ]
    25. }
    26. }

    运行上述代码响应结果见下:

    二. filter过滤

    Elasticsearch使用的查询语言(DSL)拥有一套查询组件,这些组件可以以无限组合的方式进行搭配。这套组件可以在以下两种情况下使用:过滤情况(filtering context)和查询情况(query context)。

    如何选择查询与过滤?通常的规则是,使用查询(query)语句来进行全文搜索或者其它任何需要影响相关性得分的搜索。 除此以外的情况都使用过滤(filters)。

    1.条件查询中进行过滤

    所有的查询都会影响到文档的评分及排名。如果我们需要在查询结果中进行过滤,并且不希望过滤条件影响评分,那么就不要把过滤条件作为查询条件来用。而是使用filter方式:

    1. GET /yx/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "must": {
    6. "match": {
    7. "title": "小米手机"
    8. }
    9. },
    10. "filter": {
    11. "range": {
    12. "price": {
    13. "gt": 2000.00,
    14. "lt": 3800.00
    15. }
    16. }
    17. }
    18. }
    19. }
    20. }

    响应结果:

    1. {
    2. "took": 71,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 2,
    12. "max_score": 1.1143606,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "lNC7KYUB35ub5htYEZMU",
    18. "_score": 1.1143606,
    19. "_source": {
    20. "title": "小米手机",
    21. "images": "http://image.yx.com/12479122.jpg",
    22. "price": 2699
    23. }
    24. },
    25. {
    26. "_index": "yx",
    27. "_type": "goods",
    28. "_id": "1",
    29. "_score": 0.2876821,
    30. "_source": {
    31. "title": "大米手机",
    32. "images": "http://image.yx.com/12479122.jpg",
    33. "price": 2899
    34. }
    35. }
    36. ]
    37. }
    38. }

    运行上述代码响应结果见下:

    2.无查询条件直接过滤

    如果一次查询只有过滤,没有查询条件,不希望进行评分,我们可以使用constant_score取代只有filter语句的bool查询。在性能上是完全相同的,但对于提高查询简洁性和清晰度有很大帮助。

    1. GET /yx/_search
    2. {
    3. "query": {
    4. "constant_score": {
    5. "filter": {
    6. "range": {
    7. "price": {
    8. "gt": 2000.00,
    9. "lt": 3800.00
    10. }
    11. }
    12. }
    13. }
    14. }
    15. }

    响应结果:

    1. {
    2. "took": 16,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 2,
    12. "max_score": 1,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "lNC7KYUB35ub5htYEZMU",
    18. "_score": 1,
    19. "_source": {
    20. "title": "小米手机",
    21. "images": "http://image.yx.com/12479122.jpg",
    22. "price": 2699
    23. }
    24. },
    25. {
    26. "_index": "yx",
    27. "_type": "goods",
    28. "_id": "1",
    29. "_score": 1,
    30. "_source": {
    31. "title": "大米手机",
    32. "images": "http://image.yx.com/12479122.jpg",
    33. "price": 2899
    34. }
    35. }
    36. ]
    37. }
    38. }

    运行上述代码响应结果见下:

    三. 结果排序

    1.单字段排序

    sort可以让我们按照不同的字段进行排序,并且通过order属性指定排序的方式。

    属性

    描述

    asc

    升序排序

    desc

    降序排序

    演示案例:

    1. GET /yx/_search
    2. {
    3. "query": {
    4. "match": {
    5. "title": "小米手机"
    6. }
    7. },
    8. "sort": [
    9. {
    10. "price": {
    11. "order": "desc"
    12. }
    13. }
    14. ]
    15. }

    响应结果:

    1. {
    2. "took": 31,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 5,
    12. "max_score": null,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "4",
    18. "_score": null,
    19. "_source": {
    20. "title": "Apple手机",
    21. "images": "http://image.yx.com/12479122.jpg",
    22. "price": 6899
    23. },
    24. "sort": [
    25. 6899
    26. ]
    27. },
    28. {
    29. "_index": "yx",
    30. "_type": "goods",
    31. "_id": "2",
    32. "_score": null,
    33. "_source": {
    34. "title": "IPhone手机",
    35. "images": "http://image.yx.com/12479122.jpg",
    36. "price": 6299,
    37. "stock": 200,
    38. "saleable": true,
    39. "subTitle": "IPhone 15 Pro"
    40. },
    41. "sort": [
    42. 6299
    43. ]
    44. },
    45. {
    46. "_index": "yx",
    47. "_type": "goods",
    48. "_id": "5",
    49. "_score": null,
    50. "_source": {
    51. "title": "小米电视4A",
    52. "images": "http://images.com",
    53. "price": 3999
    54. },
    55. "sort": [
    56. 3999
    57. ]
    58. },
    59. {
    60. "_index": "yx",
    61. "_type": "goods",
    62. "_id": "1",
    63. "_score": null,
    64. "_source": {
    65. "title": "大米手机",
    66. "images": "http://image.yx.com/12479122.jpg",
    67. "price": 2899
    68. },
    69. "sort": [
    70. 2899
    71. ]
    72. },
    73. {
    74. "_index": "yx",
    75. "_type": "goods",
    76. "_id": "lNC7KYUB35ub5htYEZMU",
    77. "_score": null,
    78. "_source": {
    79. "title": "小米手机",
    80. "images": "http://image.yx.com/12479122.jpg",
    81. "price": 2699
    82. },
    83. "sort": [
    84. 2699
    85. ]
    86. }
    87. ]
    88. }
    89. }

    2.多字段排序

    假定我们想要结合使用price和_score(得分)进行查询,并且匹配的结果首先按照价格排序,然后再按照相关性得分降序排序:

    1. GET /yx/_search
    2. {
    3. "query": {
    4. "bool": {
    5. "must": {
    6. "match": {
    7. "title": "小米手机"
    8. }
    9. },
    10. "filter": {
    11. "range": {
    12. "price": {
    13. "gt": 2000,
    14. "lt": 3000
    15. }
    16. }
    17. }
    18. }
    19. },
    20. "sort": [
    21. {
    22. "price": {
    23. "order": "desc"
    24. }
    25. },
    26. {
    27. "_score": {
    28. "order": "desc"
    29. }
    30. }
    31. ]
    32. }

    响应结果:

    1. {
    2. "took": 10,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 2,
    12. "max_score": null,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "1",
    18. "_score": 0.2876821,
    19. "_source": {
    20. "title": "大米手机",
    21. "images": "http://image.yx.com/12479122.jpg",
    22. "price": 2899
    23. },
    24. "sort": [
    25. 2899,
    26. 0.2876821
    27. ]
    28. },
    29. {
    30. "_index": "yx",
    31. "_type": "goods",
    32. "_id": "lNC7KYUB35ub5htYEZMU",
    33. "_score": 1.1143606,
    34. "_source": {
    35. "title": "小米手机",
    36. "images": "http://image.yx.com/12479122.jpg",
    37. "price": 2699
    38. },
    39. "sort": [
    40. 2699,
    41. 1.1143606
    42. ]
    43. }
    44. ]
    45. }
    46. }

    四. 分页查询

    Elasticsearch中数据都存储在分片中,当执行搜索时每个分片独立搜索后,数据再经过整合返回。那么,如果要实现分页查询该怎么办呢?

    Elasticsearch的分页与MySQL数据库非常相似,都是指定两个值:

    属性

    描述

    from

    目标数据的偏移值(开始位置),默认from为0

    size

    每页大小

    演示案例:

    1. GET /yx/_search
    2. {
    3. "query": {
    4. "match_all": {}
    5. },
    6. "sort": [
    7. {
    8. "price": {
    9. "order": "desc"
    10. }
    11. }
    12. ],
    13. "from": 1,
    14. "size": 3
    15. }

    响应结果:

    1. {
    2. "took": 17,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 5,
    12. "max_score": null,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "2",
    18. "_score": null,
    19. "_source": {
    20. "title": "IPhone手机",
    21. "images": "http://image.yx.com/12479122.jpg",
    22. "price": 6299,
    23. "stock": 200,
    24. "saleable": true,
    25. "subTitle": "IPhone 15 Pro"
    26. },
    27. "sort": [
    28. 6299
    29. ]
    30. },
    31. {
    32. "_index": "yx",
    33. "_type": "goods",
    34. "_id": "3",
    35. "_score": null,
    36. "_source": {
    37. "title": "小米电视4A",
    38. "images": "http://image.yx.com/12479122.jpg",
    39. "price": 3899
    40. },
    41. "sort": [
    42. 3899
    43. ]
    44. }
    45. ]
    46. }
    47. }

    五. 高亮显示

    1.高亮显示原理

    高亮显示的原理介绍见下:

    • 服务端搜索数据,得到搜索结果。
    • 把搜索结果中,搜索关键字都加上约定好的标签。
    • 前端页面提前写好标签的CSS样式,即可高亮显示。

    Elasticsearch中实现高亮的语法比较简单,高亮显示语法格式见下:

    1. GET /索引库名/_search
    2. {
    3. "query": {
    4. "match": {
    5. "字段": "字段值"
    6. }
    7. },
    8. "highlight": {
    9. "pre_tags": "前置标签",
    10. "post_tags": "后置标签",
    11. "fields": {
    12. "高亮字段名": {}
    13. }
    14. }
    15. }

    在使用match查询的同时,加上一个highlight属性。highlight属性提供以下属性:

    属性

    描述

    pre_tags

    前置标签

    post_tags

    后置标签

    fields

    需要高亮的字段(例如这里声明title字段需要高亮)

    2.高亮显示案例

    演示案例:

    1. GET /yx/_search
    2. {
    3. "query": {
    4. "match": {
    5. "title": "手机"
    6. }
    7. },
    8. "highlight": {
    9. "pre_tags": "",
    10. "post_tags": "",
    11. "fields": {
    12. "title": {}
    13. }
    14. }
    15. }

    响应结果:

    1. {
    2. "took": 19,
    3. "timed_out": false,
    4. "_shards": {
    5. "total": 5,
    6. "successful": 5,
    7. "skipped": 0,
    8. "failed": 0
    9. },
    10. "hits": {
    11. "total": 4,
    12. "max_score": 0.2876821,
    13. "hits": [
    14. {
    15. "_index": "yx",
    16. "_type": "goods",
    17. "_id": "1",
    18. "_score": 0.2876821,
    19. "_source": {
    20. "title": "大米手机",
    21. "images": "http://image.yx.com/12479122.jpg",
    22. "price": 2899
    23. },
    24. "highlight": {
    25. "title": [
    26. "大米手机"
    27. ]
    28. }
    29. },
    30. {
    31. "_index": "yx",
    32. "_type": "goods",
    33. "_id": "lNC7KYUB35ub5htYEZMU",
    34. "_score": 0.13353139,
    35. "_source": {
    36. "title": "小米手机",
    37. "images": "http://image.yx.com/12479122.jpg",
    38. "price": 2699
    39. },
    40. "highlight": {
    41. "title": [
    42. "小米手机"
    43. ]
    44. }
    45. },
    46. {
    47. "_index": "yx",
    48. "_type": "goods",
    49. "_id": "2",
    50. "_score": 0.13353139,
    51. "_source": {
    52. "title": "IPhone手机",
    53. "images": "http://image.yx.com/12479122.jpg",
    54. "price": 6299,
    55. "stock": 200,
    56. "saleable": true,
    57. "subTitle": "IPhone 15 Pro"
    58. },
    59. "highlight": {
    60. "title": [
    61. "IPhone手机"
    62. ]
    63. }
    64. },
    65. {
    66. "_index": "yx",
    67. "_type": "goods",
    68. "_id": "4",
    69. "_score": 0.13353139,
    70. "_source": {
    71. "title": "Apple手机",
    72. "images": "http://image.yx.com/12479122.jpg",
    73. "price": 6899
    74. },
    75. "highlight": {
    76. "title": [
    77. "Apple手机"
    78. ]
    79. }
    80. }
    81. ]
    82. }
    83. }

    运行上述代码响应结果见下:

    六. 结语

    关于Elasticsearch高级查询篇相关的内容我们就给大家介绍完了,来复习回顾下这一章节的主要内容。本文从结果过滤查询、结果排序、分页查询、检索查询、关键字查询、高亮显示、过滤查询等几个方面通过实例讲解了Elasticsearch的高级查询。如果还没有掌握的小伙伴,一定要通过文章中大量的案例来进行实操演练从而巩固这一部分知识。下一小节我们将为大家带来Elasticsearch中聚合操作相关的内容。

    今天的内容就分享到这里吧。关注「袁庭新」,干货天天都不断!

  • 相关阅读:
    自然辩证法2023年预测考点
    基于web在线餐饮网站的设计与实现——仿Coco线上订奶茶饮料6个页面(HTML+CSS+JavaScript)
    Python科学计算与可视化 C1
    Electron学习——解决npm install electron --save-dev出错/缓慢的问题
    【python】(十二)python内置库——文件处理
    “Cloud“(云)
    k8s核心操作_k8s中的存储抽象_基本概念与NFS搭建_Deployment使用NFS进行挂载---分布式云原生部署架构搭建028
    uniapp/手机APP使用支付宝支付(服务端)
    XTU OJ 1170 学习笔记
    VIT 源码详解
  • 原文地址:https://blog.csdn.net/2301_82300081/article/details/136318960