首页 > 其他分享 >ElasticSearch入门到掌握,用心看完这三篇就够了【完结2】

ElasticSearch入门到掌握,用心看完这三篇就够了【完结2】

时间:2024-09-04 10:24:21浏览次数:7  
标签:词条 hotel 就够 查询 score 文档 query 用心看 ElasticSearch

文章目录

「章节总览」
 
      【ElasticSearch 第一篇 https://blog.csdn.net/weixin_45404884/article/details/137402463】
      【ElasticSearch 第二篇 https://blog.csdn.net/weixin_45404884/article/details/137505489】
      【ElasticSearch 第三篇 https://blog.csdn.net/weixin_45404884/article/details/137548120】

二、ElasticSearch详解

1.DSL 查询文档

(1)DSL 查询语法分类

Elasticsearch 提供了基于 JSON 的 DSL ( Domain Specific Language)来定义查询。常见的查询类型包括:

  • 查询所有:查询出所有数据,一般测试用。例如: match_all
  • 全文检索( full text )查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:
    • match_query
    • multi_match_query
  • 精确查询:根据精确词条值查找数据,一般是查找 keyword 、数值、日期、 boolean 等类型字段。例如:
    • ids
    • range
    • term
  • 地理( geo )查询:根据经纬度查询。例如:
    • geo_distance
    • geo_bounding_box
  • 复合( compound )查询:复合查询可以将上述各种查询条件组合起来,合并查询条件。例如:
    • bool
    • function_score

(2)DSL Query 基本语法

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

(3)查询所有

GET /hotel/_search
{
  "query": {
    "match_all": {}
  }
}

(4)全文检索查询

全文检索查询,会对用户输入内容分词,常用于搜索框搜索:

  • match查询,根据一个字段查询。
GET /hotel/_search
{
  "query": {
    "match": {
      "city": "杭州"
    }
  }
}
  • multi_match查询,根据多个字段查询,参与查询字段越多,查询性能越差。
GET /hotel/_search
{
  "query": {
    "multi_match": {
      "query": "四",
      "fields": [
        "star_name",
        "name"
      ]
    }
  }
}

搜索结果:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 1.2039728,
    "hits": [
      {
        "_index": "hotel",
        "_id": "2",
        "_score": 1.2039728,
        "_source": {
          "name": "李四",
          "email": "[email protected]",
          "price": 43,
          "score": 56,
          "brand": "如家",
          "city": "北京",
          "star_name": "三星",
          "business": "天安门",
          "location": "23.4234234,34.32131",
          "pic": "/1/2/3"
        }
      },
      {
        "_index": "hotel",
        "_id": "3",
        "_score": 0.6931471,
        "_source": {
          "name": "王五",
          "email": "[email protected]",
          "price": 78,
          "score": 43,
          "brand": "贝壳",
          "city": "杭州",
          "star_name": "四星",
          "business": "西湖",
          "location": "23.4234234,34.32131",
          "pic": "/1/2/3"
        }
      },
      {
        "_index": "hotel",
        "_id": "4",
        "_score": 0.6931471,
        "_source": {
          "name": "赵六",
          "email": "[email protected]",
          "price": 78,
          "score": 43,
          "brand": "贝壳",
          "city": "杭州",
          "star_name": "四星",
          "business": "西湖",
          "location": "23.4234234,34.32131",
          "pic": "/1/2/3"
        }
      }
    ]
  }
}

(5)精确查询

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

  • term :根据词条精确值查询,根据词条精确匹配,一般搜索 keyword 类型、数值类型、布尔类型、日期类型字段。
GET /hotel/_search
{
  "query": {
    "term": {
      "city": {
        "value": "上海"
      }
    }
  }
}
  • range :根据值的范围查询
GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 70,
        "lte": 80
      }
    }
  }
}

(6)地理查询

根据经纬度查询。常见的使用场景包括:

  • 携程:搜索我附近的酒店
  • 滴滴:搜索我附近的出租车
  • 微信:搜索我附近的人

例如:

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

请添加图片描述

GET /hotel/_search
{
  "query": {
    "geo_bounding_box": {
      "location": {
        "top_left": {
          "lat": 24,
          "lon": 35
        },
        "bottom_right": {
          "lat": 22,
          "lon": 33
        }
      }
    }
  }
}
  • geo_distance :查询到指定中心点小于某个距离值的所有文档
    请添加图片描述
GET /hotel/_search
{
  "query": {
    "geo_distance": {
      "distance": "500km",
      "location": "22,33"
    }
  }
}

(7)复合查询

相关性算分

当我们利用 match 查询时,文档结果会根据与搜索词条的关联度打分( _score ),返回结果时按照分值降序排列。

 - F-IDF :在 elasticsearch5.0 之前,会随着词频增加而越来越大。
 - BM25 :在 elasticsearch5.0 之后,会随着词频增加而增大,但增长曲线会趋于水平。

TF算法:
T F ( 词条频率 ) = 词条出现次数 文档中词条总数 TF(词条频率) = \dfrac{词条出现次数}{文档中词条总数} {} TF(词条频率)=文档中词条总数词条出现次数​

TF- IDF算法:
I D F ( 逆文档频率 ) = log ⁡ ( 文档总数 包含词条的文档总数 ) IDF(逆文档频率) =\log( \dfrac{文档总数}{包含词条的文档总数} {}) IDF(逆文档频率)=log(包含词条的文档总数文档总数​)
s c o r e = ∑ i n T F ( 词条频率 ) ∗ I D F ( 逆文档频率 ) score =\sum \limits_{i}^nTF(词条频率) * IDF(逆文档频率) score=i∑n​TF(词条频率)∗IDF(逆文档频率)

BM25算法
s c o r e ( Q , d ) = ∑ i n log ⁡ ( 1 + N − n + 0.5 n + 0.5 ∗ f i f i + k 1 ∗ ( 1 − b + b ∗ d l a v g d l ) ) score(Q,d) =\sum \limits_{i}^n \log(1+ \dfrac{N-n+0.5}{n+0.5} * \dfrac{f_i}{f_i+k_1 * (1-b+b*\dfrac{dl}{avgdl})}) score(Q,d)=i∑n​log(1+n+0.5N−n+0.5​∗fi​+k1​∗(1−b+b∗avgdldl​)fi​​)

fuction score

算分函数查询,可以控制文档相关性算分,控制文档排名。
- 过滤条件:哪些文档要加分
- 算分函数:如何计算 function score
- 加权方式: function score 与 query score 如何运算

GET /hotel/_search
{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "all": " 外滩 "
        }
      },
      "functions": [
        {
          "filter": {
            "term": {
              "id": "1"
            }
          },
          "weight": 10
        }
      ],
      "boost_mode": "multiply"
    }
  }
}

请添加图片描述

bool 查询

布尔查询是一个或多个查询子句的组合。子查询的组合方式有:

  • must :必须匹配每个子查询,类似“与”
  • should :选择性匹配子查询,类似“或”
  • must_not :必须不匹配,不参与算分,类似“非”
  • filter :必须匹配,不参与算分
##搜索品牌包含“如家”,价格不高于400 ,在坐标 23.21,33.5 周围 1000km范围内的酒店。
GET /hotel/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "brand": "如家"
          }
        }
      ],
      "must_not": [
        {
          "range": {
            "price": {
              "gt": 400
            }
          }
        }
      ],
      "filter": [
        {
          "geo_distance": {
            "distance": "1000km",
            "location": {
              "lat": 23.21,
              "lon": 33.5
            }
          }
        }
      ]
    }
  }
}

2. 搜索结果处理

(1)排序

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

GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "price": "desc" // 排序字段和排序方式 ASC 、 DESC
    }
    ]
}

(2)分页

elasticsearch 默认情况下只返回 top10 的数据。而如果要查询更多数据就需要修改分页参数了。
elasticsearch 中通过修改 from 、 size 参数来控制要返回的分页结果:

GET /hotel/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0, // 分页开始的位置,默认为0
  "size": 10, // 期望获取的文档总数
  "sort": [
    {"price": "asc"}
    ]
}

(3)深度分页问题

ES 是分布式的,所以会面临深度分页问题。例如按 price 排序后,获取 from = 990 , size =10 的数据:
聚合所有结果,重新排序选取前 1000 个。

  1. 首先在每个数据分片上都排序并查询前1000 条文档。
  2. 然后将所有节点的结果聚合,在内存中重新排序选出前 1000 条文档。
  3. 最后从这 1000 条中,选取从 990 开始的10 条文档。
    如果搜索页数过深,或者结果集( from +size )越大,对内存和 CPU 的消耗也越高。因此 ES 设定结果集查询的上限是 10000。
    针对深度分页, ES 提供了两种解决方案,官方文档:
    • search after :分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。官方推荐使用的方式。
    • scroll :原理将排序数据形成快照,保存在内存。官方已经不推荐使用。

(4)高亮

高亮:就是在搜索结果中把搜索关键字突出显示。
原理是这样的:

  • 将搜索结果中的关键字用标签标记出来
  • 在页面中给标签添加 css 样式
GET /hotel/_search
{
  "query": {
    "term": {
      "city": {
        "value": "上海"
      }
    }
  },
  "highlight": {
    "fields": {
      "city": {
        "pre_tags": "<em>",
        "post_tags": "<em>"
      }
    }
  }
}

返回结果以高亮形式返回:

{
  "took": 0,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.6486585,
    "hits": [
      {
        "_index": "hotel",
        "_id": "1",
        "_score": 1.6486585,
        "_source": {
          "name": "张三",
          "email": "[email protected]",
          "price": 12,
          "score": 12,
          "brand": "汉庭",
          "city": "上海",
          "star_name": "五星",
          "business": "虹桥",
          "location": "23.423424, 34.32131",
          "pic": "/1/2/3"
        },
        "highlight": {
          "city": [
            "<em>上海<em>"
          ]
        }
      }
    ]
  }
}

3.RestClient 查询文档

(1)查询所有

@Test
    public void testMatchAll() throws IOException {
        RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://localhost:9200")
        ));
        try {
            // 1.准备 Request
            SearchRequest request = new SearchRequest("hotel");
            // 2.组织 DSL参数
            request.source().query(QueryBuilders.matchAllQuery());
            // 3.发送请求,得到响应结果
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //解析响应结果
            SearchHits searchHits = response.getHits();
            // 4.1.查询的总条数
            long total = searchHits.getTotalHits().value;
            // 4.2.查询的结果数组
            SearchHit[] hits = searchHits.getHits();
            for (SearchHit hit : hits) {
                // 4.3.得到 source
                String json = hit.getSourceAsString();
                System.out.println(json);
            }
        }finally {
            client.close();
        }

    }

(2)全文检索查询

全文检索的 match 和 multi_match 查询与 match_all 的 API 基本一致。差别是查询条件,也就是 query 的部分。
同样是利用 QueryBuilders 提供的方法:

//单字段查询
QueryBuilders.matchQuery("all", " 如家 ");
//多字段查询
QueryBuilders.multiMatchQuery(" 如家 ", "name", "business");

(3)精确查询

精确查询常见的有 term 查询和 range 查询,同样利用 QueryBuilders 实现:

//词条查询
QueryBuilders.termQuery("city", " 杭州 ");
//范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);

(4)复合查询

精确查询常见的有 term 查询和 range 查询,同样利用 QueryBuilders 实现:

//创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//添加 must条件
boolQuery.must(QueryBuilders.termQuery("city", " 杭州 "));
//添加 filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));

(5)排序和分页

//查询
request.source().query(QueryBuilders.matchAllQuery());
//分页
request.source().from(0).size(5);
//价格排序
request.source().sort("price", SortOrder.ASC);

(6)高亮

请求request

request.source().highlighter(new HighlightBuilder().field("name")
//是否需要与查询字段匹配
.requireFieldMatch(false));

高亮处理

//获取 source
HotelDoc hotelDoc = JSON.parseObject(hit.getSourceAsString(),
HotelDoc.class);
//处理高亮
Map<String, HighlightField> highlightFields =
hit.getHighlightFields();
if (!CollectionUtils.isEmpty(highlightFields)) {
//获取高亮字段结果
HighlightField highlightField = highlightFields.get("name");
if (highlightField != null) {
//取出高亮结果数组中的第一个,就是酒店名称
String name = highlightField.getFragments()[0].string();
hotelDoc.setName(name);
}
}

下一篇
https://blog.csdn.net/weixin_45404884/article/details/137548120

标签:词条,hotel,就够,查询,score,文档,query,用心看,ElasticSearch
From: https://blog.csdn.net/weixin_45404884/article/details/137505489

相关文章

  • ElasticSearch 备考 -- Runtime Field
    一、题目在集群上有索引task,请编写查询并满足要求:定义一个名为field_num的运行时字段,实现以下聚合(a字段的值等于field_x字段减去field_y字段),field_num聚合区间如下:聚合值小于0的文档聚合0到100之间的文档聚合大于100的文档二、思考1)运行时字段第一反应runtimefil......
  • ElasticSearch 备考 -- Nested
    一、题目存在索引phones,其中存在两条数据如下PUTphones/_doc/1{  "brand":"Samsumg",  "model":"GalaxyS9+",  "features":[    {      "type":"os",      "value":&......
  • 搞懂Transformer结构,看这篇PyTorch实现就够了
    前言下面分享一篇实验室翻译的来自哈佛大学一篇关于Transformer的详细博文。“AttentionisAllYouNeed”[1]一文中提出的Transformer网络结构最近引起了很多人的关注。Transformer不仅能够明显地提升翻译质量,还为许多NLP任务提供了新的结构。虽然原文写得很清楚,但实际上大家普......
  • CSS-transition过渡动画【看这一篇就够了!!】
    目录transition过渡动画transition基本语法用法实际应用可参与过渡的属性不能参与过渡的属性all特殊属性定义多个过渡动画过渡的四个小属性时间函数时间函数的预设值常用参数贝塞尔曲线transition过渡动画实战案例鼠标滑动,背景从透明到半透明的效果鼠标滑动文......
  • 图算法太难懂?凸包算法搞不通?看这篇文章就够了
    标题:你以为凸包算法只是数学游戏?不,这才是竞赛中的制胜法宝!你以为几何算法只是竞赛中的小儿科,顶多画个漂亮图形?但是,朋友,你要知道,如果你还停留在这样的认知,那你已经out了!凸包(ConvexHull)——听起来像个不起眼的小问题,但实际上,它是算法竞赛中的核武器,是能让你在众多参赛者中脱......
  • elasticsearch数据导出和导出
    数据导入和导出依赖于命令elasticdump数据导出#!/bin/bashES=http://ip:portED=数据保存位置datename=$(date+%Y-%m-%d)#datename=2021-08-20index=导出的索引名echo"elasticdump--input=$ES/$index--output=$ED/$index.json"elasticdump--input=$ES/$......
  • LLM大模型学习:重磅首发!大模型LLM学习路线图来了!非常详细收藏我这一篇就够了
    ChatGPT的出现在全球掀起了AI大模型的浪潮,2023年可以被称为AI元年,AI大模型以一种野蛮的方式,闯入你我的生活之中。从问答对话到辅助编程,从图画解析到自主创作,AI所展现出来的能力,超出了多数人的预料,让不少人惊呼:“未来是属于AI的”。AI大模型——成为互联网从业者必备技能。......
  • 科普文:软件架构Elasticsearch系列之【2024年8月30日 Shay:Elasticsearch is Open Sourc
     2021年1月,当时Elastic公司决定把Elasticsearch和Kibana的许可证从Apache2.0变更为ElasticLicense2.0(ELv2)和ServerSidePublicLicense(SSPL)双许可。尽管这两个许可证也允许源代码公开,但它们并不符合开源倡议组织(OSI)的开源定义。应对质疑:“本就是一个错误,现......
  • linux进程间通信——信号量(通俗易懂,看这一篇就够了)
    信号量概念特点信号量实际是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。很多进程会访问同一资源,或者向共享内存写入一些东西,为防止争夺资源混乱。可以给一些进程上锁,让其排队等待工作原理P(sv):如果sv的值大于零,就给它减1;如果它的值为......
  • 大模型LLM学习路线图2024年最新版!全面掌握学习路径,非常详细,想学大模型收藏这一篇就够
    ChatGPT的出现在全球掀起了AI大模型的浪潮,2023年可以被称为AI元年,AI大模型以一种野蛮的方式,闯入你我的生活之中。从问答对话到辅助编程,从图画解析到自主创作,AI所展现出来的能力,超出了多数人的预料,让不少人惊呼:“未来是属于AI的”。AI大模型——成为互联网从业者必备技能。......