微信平台的微网站怎么做的,网站建设项目开发,网站开发的推荐,网站制作软件dw文章目录前言概念DSL 的核心特点一、DSL设置查询条件1.1 DSL查询分类1.2 全文检索查询1.2.1 使用场景1.2.2 match查询1.2.3 mulit_match查询1.3 精准查询1.3.1 term查询1.3.2 range查询1.4 地理坐标查询1.4.1 矩形范围查询1.4.2 附近(圆形)查询1.5 复合查询1.5.0 复合查询归纳1…文章目录前言概念DSL 的核心特点一、DSL设置查询条件1.1 DSL查询分类1.2 全文检索查询1.2.1 使用场景1.2.2 match查询1.2.3 mulit_match查询1.3 精准查询1.3.1 term查询1.3.2 range查询1.4 地理坐标查询1.4.1 矩形范围查询1.4.2 附近(圆形)查询1.5 复合查询1.5.0 复合查询归纳1.5.1 相关性算分1.5.2 算分函数查询function score 查询1.5.3 布尔查询bool查询二、设置搜索结果2.0 搜索结果种类2.1 排序2.1.1普通字段排序2.1.2 地理坐标排序2.2 分页2.2.1 基本分页2.2.2 深度分页2.3 高亮高亮原理实现高亮2.4 数据聚合2.4.1 聚合种类2.4.2 桶(Bucket)聚合2.4.3 度量(Metric) and 管道(pipeline)聚合三、RestClient查询文档3.1 快速入门3.1.1 发送查询请求3.1.2 解析响应结果3.1.3 完整代码3.2 设置查询条件3.2.1 全文检索查询3.2.2 精准查询3.2.3 地理查询3.2.4 布尔查询3.2.5 算分函数查询3.3 设置搜索结果3.3.1 排序和分页3.3.2 高亮3.3.3 聚合前言DSLDomain Specific LanguageDomain-Specific LanguageDSL领域特定语言是一种专为特定应用领域设计的计算机语言。语法和语义紧密贴合某一特定问题域旨在提高该领域内开发或表达的简洁性、可读性和安全性。概念Domain-Specific LanguageDSL领域特定语言是一种专为特定应用领域设计的计算机语言与通用编程语言如 Python、Java、C不同DSL 的语法和语义紧密贴合某一特定问题域旨在提高该领域内开发或表达的简洁性、可读性和安全性。DSL 的核心特点特性说明专注性只解决某一类问题如数据库查询、配置管理、数学建模等高表达力用接近领域专家自然语言的方式描述逻辑受限性功能有限不追求图灵完备但有些 DSL 是图灵完备的易用性非程序员如业务分析师、运维人员也能理解和编写一、DSL设置查询条件1.1 DSL查询分类Elasticsearch的查询依然是基于JSON风格的DSLDomain Specific Language来定义。常见的查询类型包括查询所有查询出所有数据一般测试用。例如match_all全文检索full text查询利用分词器对用户输入内容分词然后去倒排索引库中匹配。例如match_querymulti_match_query精确查询根据精确词条值查找数据一般是查找keyword、数值、日期、boolean等类型字段。例如idsrangeterm地理geo查询根据经纬度查询。例如geo_distancegeo_bounding_box复合compound查询复合查询可以将上述各种查询条件组合起来合并查询条件。例如boolfunction_score查询的语法基本一致GET/indexName/_search{query:{查询类型:{查询条件:条件值}}}我们以查询所有为例其中查询类型为match_all没有查询条件// 查询所有GET/indexName/_search{query:{match_all:{}}}其它查询无非就是查询类型、查询条件的变化。1.2 全文检索查询match和multi_match的区别是什么match根据一个字段查询【推荐使用copy_to构造all字段】multi_match根据多个字段查询参与查询字段越多查询性能越差注搜索字段越多对查询性能影响越大因此建议采用copy_to然后单字段查询的方式。1.2.1 使用场景全文检索查询的基本流程如下对用户搜索的内容做分词得到词条根据词条去倒排索引库中匹配得到文档id根据文档id找到文档返回给用户比较常用的场景包括商城的输入框搜索百度输入框搜索例如京东因为是拿着词条去匹配因此参与搜索的字段也必须是可分词的text类型的字段。常见的全文检索查询包括match查询单字段查询multi_match查询多字段查询任意一个字段符合条件就算符合查询条件1.2.2 match查询match查询语法如下GET/indexName/_search{query:{match:{FIELD:TEXT}}}match查询示例1.2.3 mulit_match查询mulit_match语法如下GET/indexName/_search{query:{multi_match:{query:TEXT,fields:[FIELD1, FIELD12]}}}multi_match查询示例1.3 精准查询精准查询类型term查询根据词条精确匹配一般搜索keyword类型、数值类型、布尔类型、日期类型字段range查询根据数值范围查询可以是数值、日期的范围精确查询一般是查找keyword、数值、日期、boolean等类型字段。所以不会对搜索条件分词。常见的有term根据词条精确值查询range根据值的范围查询1.3.1 term查询因为精确查询的字段搜时不分词的字段因此查询的条件也必须是不分词的词条。查询时用户输入的内容跟自动值完全匹配时才认为符合条件。如果用户输入的内容过多反而搜索不到数据。语法说明// term查询GET/indexName/_search{query:{term:{FIELD:{value:VALUE}}}}示例当我搜索的是精确词条时能正确查询出结果但是当我搜索的内容不是词条而是多个词语形成的短语时反而搜索不到1.3.2 range查询范围查询一般应用在对数值类型做范围过滤的时候。比如做价格范围过滤。基本语法// range查询GET/indexName/_search{query:{range:{FIELD:{gte:10,// 这里的gte代表大于等于gt则代表大于lte:20// lte代表小于等于lt则代表小于}}}}示例1.4 地理坐标查询所谓的地理坐标查询其实就是根据经纬度查询官方文档https://www.elastic.co/guide/en/Elasticsearch/reference/current/geo-queries.html常见的使用场景包括携程搜索我附近的酒店滴滴搜索我附近的出租车微信搜索我附近的人附近的酒店附近的车1.4.1 矩形范围查询很少有业务有这种需求矩形范围查询也就是geo_bounding_box查询查询坐标落在某个矩形范围的所有文档查询时需要指定矩形的左上、右下两个点的坐标然后画出一个矩形落在该矩形内的都是符合条件的点。语法如下// 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}}}}}1.4.2 附近(圆形)查询附近查询也叫做距离查询geo_distance查询到指定中心点小于某个距离值的所有文档。换句话来说在地图上找一个点作为圆心以指定距离为半径画一个圆落在圆内的坐标都算符合条件语法说明// geo_distance 查询GET/indexName/_search{query:{geo_distance:{distance:15km,// 半径FIELD:31.21,121.5// 圆心}}}示例我们先搜索陆家嘴附近15km的酒店发现共有47家酒店。1.5 复合查询复合compound查询复合查询可以将其它简单查询组合起来实现更复杂的搜索逻辑。常见的有两种fuction score算分函数查询可以控制文档相关性算分控制文档排名bool query布尔查询利用逻辑关系组合多个其它的查询实现复杂搜索1.5.0 复合查询归纳GET/hotel/_search{query:{function_score:{query:{// 原始查询可以是任意条件bool:{must:[{term:{city:上海}}],should:[{term:{brand:皇冠假日}},{term:{brand:华美达}}],must_not:[{range:{price:{lte:500}}}],filter:[{range:{score:{gte:45}}}]}},functions:[// 算分函数{filter:{// 满足的条件品牌必须是如家【品牌是如家的才加分这里是加分条件】term:{brand:如家}},weight:2// 算分权重为2}],boost_mode:sum// 加权模式求和}}}1.5.1 相关性算分Elasticsearch会根据词条和文档的相关度做打分算法由两种TF-IDF算法BM25算法Elasticsearch5.1版本后采用的算法当我们利用match查询时文档结果会根据与搜索词条的关联度打分_score返回结果时按照分值降序排列。例如我们搜索 “虹桥如家”结果如下[{_score:17.850193,_source:{name:虹桥如家酒店真不错,}},{_score:12.259849,_source:{name:外滩如家酒店真不错,}},{_score:11.91091,_source:{name:迪士尼如家酒店真不错,}}]在Elasticsearch中早期使用的打分算法是TF-IDF算法公式如下在后来的5.1版本升级中Elasticsearch将算法改进为BM25算法公式如下TF-IDF算法有一各缺陷就是词条频率越高文档得分也会越高单个词条对文档影响较大。而BM25则会让单个词条的算分有一个上限曲线更加平滑1.5.2 算分函数查询在搜索出来的结果的分数基础上再手动与指定的数字进行一定运算来改变算分从而改变结果的排序。function score query定义的三要素是什么过滤条件哪些文档要加分算分函数如何计算function score加权方式function score 与 query score如何运算根据相关度打分是比较合理的需求但合理的不一定是产品经理需要的。以百度为例你搜索的结果中并不是相关度越高排名越靠前而是谁掏的钱多排名就越靠前。如图要想认为控制相关性算分就需要利用Elasticsearch中的function score 查询了。function score 查询1语法说明function score 查询中包含四部分内容原始查询条件query部分基于这个条件搜索文档并且基于BM25算法给文档打分原始算分query score)过滤条件filter部分符合该条件的文档才会重新算分算分函数符合filter条件的文档要根据这个函数做运算得到的函数算分function score有四种函数weight函数结果是常量field_value_factor以文档中的某个字段值作为函数结果random_score以随机数作为函数结果script_score自定义算分函数算法运算模式算分函数的结果、原始查询的相关性算分两者之间的运算方式包括multiply相乘replace用function score替换query score其它例如sum、avg、max、minfunction score的运行流程如下1根据原始条件查询搜索文档并且计算相关性算分称为原始算分query score2根据过滤条件过滤文档3符合过滤条件的文档基于算分函数运算得到函数算分function score4将原始算分query score和函数算分function score基于运算模式做运算得到最终结果作为相关性算分。2举例需求给“如家”这个品牌的酒店排名靠前一些翻译一下这个需求转换为之前说的四个要点原始条件不确定可以任意变化过滤条件brand “如家”算分函数可以简单粗暴直接给固定的算分结果weight运算模式比如求和因此最终的DSL语句如下GET/hotel/_search{query:{function_score:{query:{....},// 原始查询可以是任意条件functions:[// 算分函数{filter:{// 满足的条件品牌必须是如家【品牌是如家的才加分这里是加分条件】term:{brand:如家}},weight:2// 算分权重为2}],boost_mode:sum// 加权模式求和}}}测试在未添加算分函数时如家得分如下添加了算分函数后如家得分就提升了1.5.3 布尔查询布尔查询是一个或多个查询子句的组合每一个子句就是一个子查询。子查询的组合方式有must必须匹配每个子查询类似“与”should选择性匹配子查询类似“或”must_not必须不匹配不参与算分类似“非”filter必须匹配不参与算分注意尽量在筛选的时候多使用不参与算分的must_not和filter以保证性能良好比如在搜索酒店时除了关键字搜索外我们还可能根据品牌、价格、城市等字段做过滤每一个不同的字段其查询的条件、方式都不一样必须是多个不同的查询而要组合这些查询就必须用bool查询了。需要注意的是搜索时参与打分的字段越多查询的性能也越差。因此这种多条件查询时建议这样做搜索框的关键字搜索是全文检索查询使用must查询参与算分其它过滤条件采用filter查询。不参与算分bool查询1语法GET/hotel/_search{query:{bool:{must:[{term:{city:上海}}],should:[{term:{brand:皇冠假日}},{term:{brand:华美达}}],must_not:[{range:{price:{lte:500}}}],filter:[{range:{score:{gte:45}}}]}}}2示例需求搜索名字包含“如家”价格不高于400在坐标31.21,121.5周围10km范围内的酒店。分析名称搜索属于全文检索查询应该参与算分。放到must中价格不高于400用range查询属于过滤条件不参与算分。放到must_not中周围10km范围内用geo_distance查询属于过滤条件不参与算分。放到filter中二、设置搜索结果搜索的结果可以按照用户指定的方式去处理或展示。2.0 搜索结果种类查询的DSL是一个大的JSON对象包含下列属性query查询条件from和size分页条件sort排序条件highlight高亮条件aggs定义聚合示例2.1 排序在使用排序后就不会进行算分了根据排序设置的规则排列普通字段是根据字典序排序地理坐标是根据举例远近排序2.1.1普通字段排序keyword、数值、日期类型排序的排序语法基本一致。语法排序条件是一个数组也就是可以写多个排序条件。按照声明的顺序当第一个条件相等时再按照第二个条件排序以此类推可以参考下面的图片案例GET/indexName/_search{query:{match_all:{}},sort:[{FIELD:desc// 排序字段、排序方式ASC、DESC}]}示例需求描述酒店数据按照用户评价score)降序排序评价相同的按照价格(price)升序排序2.1.2 地理坐标排序地理坐标排序略有不同。语法说明GET/indexName/_search{query:{match_all:{}},sort:[{_geo_distance:{FIELD:纬度经度,// 文档中geo_point类型的字段名、目标坐标点order:asc,// 排序方式unit:km// 排序的距离单位}}]}这个查询的含义是指定一个坐标作为目标点计算每一个文档中指定字段必须是geo_point类型的坐标 到目标点的距离是多少根据距离排序示例需求描述实现对酒店数据按照到你的位置坐标的距离升序排序提示获取你的位置的经纬度的方式获取鼠标点击经纬度-地图属性-示例中心-JS API 2.0 示例 | 高德地图API假设我的位置是31.034661121.612282寻找我周围距离最近的酒店。2.2 分页Elasticsearch会禁止from size 超过10000的请求Elasticsearch 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。Elasticsearch中通过修改from、size参数来控制要返回的分页结果from从第几个文档开始size总共查询几个文档类似于mysql中的limit ?, ?2.2.1 基本分页分页的基本语法如下GET/hotel/_search{query:{match_all:{}},from:0,// 分页开始的位置默认为0size:10,// 期望获取的文档总数sort:[{price:asc}]}2.2.2 深度分页原理Elasticsearch内部分页时必须先查询 0~1000条然后截取其中的990 ~ 1000的这10条现在我要查询990~1000的数据查询逻辑要这么写GET/hotel/_search{query:{match_all:{}},from:990,// 分页开始的位置默认为0size:10,// 期望获取的文档总数sort:[{price:asc}]}这里是查询990开始的数据也就是 第990~第1000条 数据。集群情况的深度分页针对深度分页ES提供了两种解决方案官方文档search after分页时需要排序原理是从上一次的排序值开始查询下一页数据。【官方推荐】scroll原理将排序后的文档id形成快照保存在内存。不过Elasticsearch内部分页时必须先查询 0~1000条然后截取其中的990 ~ 1000的这10条查询TOP1000如果es是单点模式这并无太大影响。但是Elasticsearch将来一定是集群例如我集群有5个节点我要查询TOP1000的数据并不是每个节点查询200条就可以了。因为节点A的TOP200在另一个节点可能排到10000名以外了。因此要想获取整个集群的TOP1000必须先查询出每个节点的TOP1000汇总结果后重新排名重新截取TOP1000。那如果我要查询9900~10000的数据呢是不是要先查询TOP10000呢那每个节点都要查询10000条汇总到内存中当查询分页深度较大时汇总数据过多对内存和CPU会产生非常大的压力因此Elasticsearch会禁止from size 超过10000的请求。2.3 高亮注意高亮是对关键字高亮因此搜索条件必须带有关键字而不能是范围这样的查询。默认情况下高亮的字段必须与搜索指定的字段一致否则无法高亮如果要对非搜索字段高亮则需要添加一个属性required_field_matchfalse使用场景在百度等搜索后会对结果中出现搜索字段的部分进行高亮处理。高亮原理高亮显示的实现分为两步1给文档中的所有关键字都添加一个标签例如em标签2页面给em标签编写CSS样式实现高亮1语法GET/hotel/_search{query:{match:{FIELD:TEXT// 查询条件高亮一定要使用全文检索查询}},highlight:{fields:{// 指定要高亮的字段FIELD:{//【要和上面的查询字段FIELD一致】pre_tags:em,// 用来标记高亮字段的前置标签post_tags:/em// 用来标记高亮字段的后置标签}}}}2示例组合字段all的案例2.4 数据聚合类似于mysql中的【**度量Metric**聚合】聚合语句实现AVGMAXMIN以及【**桶Bucket**聚合】GroupBy实现分组**聚合aggregations**可以让我们极其方便的实现对数据的统计、分析、运算。例如什么品牌的手机最受欢迎这些手机的平均价格、最高价格、最低价格这些手机每月的销售情况如何实现这些统计功能的比数据库的sql要方便的多而且查询速度非常快可以实现近实时搜索效果。aggs代表聚合与query同级此时query的作用是限定聚合的的文档范围聚合必须的三要素聚合名称聚合类型聚合字段聚合可配置属性有size指定聚合结果数量order指定聚合结果排序方式field指定聚合字段2.4.1 聚合种类**注意**参加聚合的字段必须是keyword、日期、数值、布尔类型聚合常见的有三类**桶Bucket**聚合用来对文档做分组TermAggregation按照文档字段值分组例如按照品牌值分组、按照国家分组Date Histogram按照日期阶梯分组例如一周为一组或者一月为一组**度量Metric**聚合用以计算一些值比如最大值、最小值、平均值等Avg求平均值Max求最大值Min求最小值Stats同时求max、min、avg、sum等**管道pipeline**聚合其它聚合的结果为基础做聚合如用桶聚合实现种类排序然后使用度量聚合实现各个桶的最大值、最小值、平均值等2.4.2 桶(Bucket)聚合以统计酒店品牌种类并对其进行数据分组GET/hotel/_search{query:{//限定要聚合的文档范围只要添加query条件【一般在没搜索关键字时不写query】range:{price:{lte:200// 只对200元以下的文档聚合}}},size:0,// 设置size为0结果中不包含查询结果文档只包含聚合结果aggs:{// 定义聚合brandAgg:{//给聚合起个名字terms:{// 聚合的类型按照品牌值聚合所以选择termfield:brand,// 参与聚合的字段order:{doc_count:asc// 对聚合结果按照doc_count升序排列},size:20// 希望获取的聚合结果数量【设置多少就最多只显示多少】}}}}2.4.3 度量(Metric) and 管道(pipeline)聚合度量聚合很少单独使用一般是和桶聚合一并结合使用我们对酒店按照品牌分组形成了一个个桶。现在我们需要对桶内的酒店做运算获取每个品牌的用户评分的min、max、avg等值。这就要用到Metric聚合了例如stat聚合就可以获取min、max、avg等结果。语法如下这次的score_stats聚合是在brandAgg的聚合内部嵌套的子聚合。因为我们需要在每个桶分别计算。GET/hotel/_search{size:0,aggs:{brandAgg:{terms:{field:brand,order:{scoreAgg.avg:desc// 对聚合结果按照指定字段降序排列},size:20},aggs:{// 是brands聚合的子聚合也就是分组后对每组分别计算score_stats:{// 聚合名称stats:{// 聚合类型这里stats可以计算min、max、avg等field:score// 聚合字段这里是score}}}}}}另外我们还可以给聚合结果做个排序例如按照每个桶的酒店平均分做排序三、RestClient查询文档文档的查询同样适用昨天学习的 RestHighLevelClient对象基本步骤包括1准备Request对象2准备请求参数3发起请求4解析响应3.1 快速入门查询的基本步骤是创建SearchRequest对象准备Request.source()也就是DSL。① QueryBuilders来构建查询条件② 传入Request.source() 的 query() 方法发送请求得到结果解析结果参考JSON结果从外到内逐层解析3.1.1 发送查询请求代码解读第一步创建SearchRequest对象指定索引库名第二步利用request.source()构建DSLDSL中可以包含查询、分页、排序、高亮等query()代表查询条件利用QueryBuilders.matchAllQuery()构建一个match_all查询的DSL第三步利用client.search()发送请求得到响应这里关键的API有两个一个是request.source()其中包含了查询、排序、分页、高亮等所有功能另一个是QueryBuilders其中包含match、term、function_score、bool等各种查询3.1.2 解析响应结果响应结果的解析Elasticsearch返回的结果是一个JSON字符串结构包含hits命中的结果total总条数其中的value是具体的总条数值max_score所有结果中得分最高的文档的相关性算分hits搜索结果的文档数组其中的每个文档都是一个json对象_source文档中的原始数据也是json对象因此我们解析响应结果就是逐层解析JSON字符串流程如下SearchHits通过response.getHits()获取就是JSON中的最外层的hits代表命中的结果SearchHits#getTotalHits().value获取总条数信息SearchHits#getHits()获取SearchHit数组也就是文档数组SearchHit#getSourceAsString()获取文档结果中的_source也就是原始的json文档数据3.1.3 完整代码完整代码如下TestvoidtestMatchAll()throwsIOException{// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSLrequest.source().query(QueryBuilders.matchAllQuery());// 3.发送请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);}privatevoidhandleResponse(SearchResponseresponse){// 4.解析响应SearchHitssearchHitsresponse.getHits();// 4.1.获取总条数longtotalsearchHits.getTotalHits().value;System.out.println(共搜索到total条数据);// 4.2.文档数组SearchHit[]hitssearchHits.getHits();// 4.3.遍历for(SearchHithit:hits){// 获取文档sourceStringjsonhit.getSourceAsString();// 反序列化HotelDochotelDocJSON.parseObject(json,HotelDoc.class);System.out.println(hotelDoc hotelDoc);}}3.2 设置查询条件3.2.1 全文检索查询全文检索的match和multi_match查询与match_all的API基本一致。差别是查询条件也就是query的部分。因此Java代码上的差异主要是request.source().query()中的参数了。同样是利用QueryBuilders提供的方法而结果解析代码则完全一致可以抽取并共享。完整代码如下TestvoidtestMatch()throwsIOException{// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSLrequest.source().query(QueryBuilders.matchQuery(all,如家));// 3.发送请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);}3.2.2 精准查询精确查询主要是两者term词条精确匹配range范围查询与之前的查询相比差异同样在查询条件其它都一样。查询条件构造的API如下3.2.3 地理查询DSL格式在cn.itcast.hotel.service.impl的HotelService的search方法中添加一个排序功能完整代码OverridepublicPageResultsearch(RequestParamsparams){try{// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSL// 2.1.querybuildBasicQuery(params,request);// 2.2.分页intpageparams.getPage();intsizeparams.getSize();request.source().from((page-1)*size).size(size);// 2.3.排序Stringlocationparams.getLocation();if(location!null!location.equals()){request.source().sort(SortBuilders.geoDistanceSort(location,newGeoPoint(location)).order(SortOrder.ASC).unit(DistanceUnit.KILOMETERS));}// 3.发送请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析响应returnhandleResponse(response);}catch(IOExceptione){thrownewRuntimeException(e);}}3.2.4 布尔查询布尔查询是用must、must_not、filter等方式组合其它查询代码示例如下可以看到API与其它查询的差别同样是在查询条件的构建QueryBuilders结果解析等其他代码完全不变。完整代码如下TestvoidtestBool()throwsIOException{// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSL// 2.1.准备BooleanQueryBoolQueryBuilderboolQueryQueryBuilders.boolQuery();// 2.2.添加termboolQuery.must(QueryBuilders.termQuery(city,杭州));// 2.3.添加rangeboolQuery.filter(QueryBuilders.rangeQuery(price).lte(250));request.source().query(boolQuery);// 3.发送请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);}3.2.5 算分函数查询java代码逻辑添加一个isAD字段在算分函数的filter中判断isADture就进行重新算分function_score查询结构如下对应的JavaAPI如下我们可以将之前写的boolean查询作为原始查询条件放到query中接下来就是添加过滤条件、算分函数、加权模式了。// 算分控制FunctionScoreQueryBuilderfunctionScoreQueryQueryBuilders.functionScoreQuery(// 原始查询相关性算分的查询boolQuery,// function score的数组newFunctionScoreQueryBuilder.FilterFunctionBuilder[]{// 其中的一个function score 元素newFunctionScoreQueryBuilder.FilterFunctionBuilder(// 过滤条件QueryBuilders.termQuery(isAD,true),// 算分函数ScoreFunctionBuilders.weightFactorFunction(10))});//将查询请求放入查询request.source().query(functionScoreQuery);3.3 设置搜索结果3.3.1 排序和分页由于这两个比较简单所以一起写了搜索结果的排序和分页是与query同级的参数因此同样是使用request.source()来设置。对应的API如下完整代码示例TestvoidtestPageAndSort()throwsIOException{// 页码每页大小intpage1,size5;// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSL// 2.1.queryrequest.source().query(QueryBuilders.matchAllQuery());// 2.2.排序 sortrequest.source().sort(price,SortOrder.ASC);// 2.3.分页 from、sizerequest.source().from((page-1)*size).size(5);// 3.发送请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);}3.3.2 高亮高亮的代码与之前代码差异较大有两点查询的DSL其中除了查询条件还需要添加高亮条件同样是与query同级。结果解析结果除了要解析_source文档数据还要解析高亮结果1高亮请求构建高亮请求的构建API如下上述代码省略了查询条件部分但是大家不要忘了高亮查询必须使用全文检索查询并且要有搜索关键字将来才可以对关键字高亮。完整代码如下TestvoidtestHighlight()throwsIOException{// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSL// 2.1.queryrequest.source().query(QueryBuilders.matchQuery(all,如家));// 2.2.高亮request.source().highlighter(newHighlightBuilder().field(name).requireFieldMatch(false));// 3.发送请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析响应handleResponse(response);}2高亮结果解析高亮的结果与查询的文档结果默认是分离的并不在一起。因此解析高亮的代码需要额外处理代码解读第一步从结果中获取source。hit.getSourceAsString()这部分是非高亮结果json字符串。还需要反序列为HotelDoc对象第二步获取高亮结果。hit.getHighlightFields()返回值是一个Mapkey是高亮字段名称值是HighlightField对象代表高亮值第三步从map中根据高亮字段名称获取高亮字段值对象HighlightField第四步从HighlightField中获取Fragments并且转为字符串。这部分就是真正的高亮字符串了第五步用高亮的结果替换HotelDoc中的非高亮结果完整代码如下privatevoidhandleResponse(SearchResponseresponse){// 4.解析响应SearchHitssearchHitsresponse.getHits();// 4.1.获取总条数longtotalsearchHits.getTotalHits().value;System.out.println(共搜索到total条数据);// 4.2.文档数组SearchHit[]hitssearchHits.getHits();// 4.3.遍历for(SearchHithit:hits){// 获取文档sourceStringjsonhit.getSourceAsString();// 反序列化HotelDochotelDocJSON.parseObject(json,HotelDoc.class);// 获取高亮结果MapString,HighlightFieldhighlightFieldshit.getHighlightFields();if(!CollectionUtils.isEmpty(highlightFields)){// 根据字段名获取高亮结果HighlightFieldhighlightFieldhighlightFields.get(name);if(highlightField!null){// 获取高亮值StringnamehighlightField.getFragments()[0].string();// 覆盖非高亮结果hotelDoc.setName(name);}}System.out.println(hotelDoc hotelDoc);}}3.3.3 聚合聚合条件与query条件同级别因此需要使用request.source()来指定聚合条件。聚合条件的语法聚合的结果也与查询结果不同API也比较特殊。不过同样是JSON逐层解析举例业务代码OverridepublicMapString,ListStringfilters(RequestParamsparams){try{// 1.准备RequestSearchRequestrequestnewSearchRequest(hotel);// 2.准备DSL// 2.1.query查询语句buildBasicQuery(params,request);// 2.2.设置sizerequest.source().size(0);// 2.3.聚合buildAggregation(request);// 3.发出请求SearchResponseresponseclient.search(request,RequestOptions.DEFAULT);// 4.解析结果MapString,ListStringresultnewHashMap();Aggregationsaggregationsresponse.getAggregations();// 4.1.根据品牌名称获取品牌结果ListStringbrandListgetAggByName(aggregations,brandAgg);result.put(品牌,brandList);// 4.2.根据品牌名称获取品牌结果ListStringcityListgetAggByName(aggregations,cityAgg);result.put(城市,cityList);// 4.3.根据品牌名称获取品牌结果ListStringstarListgetAggByName(aggregations,starAgg);result.put(星级,starList);returnresult;}catch(IOExceptione){thrownewRuntimeException(e);}}privatevoidbuildAggregation(SearchRequestrequest){request.source().aggregation(AggregationBuilders.terms(brandAgg).field(brand).size(100));request.source().aggregation(AggregationBuilders.terms(cityAgg).field(city).size(100));request.source().aggregation(AggregationBuilders.terms(starAgg).field(starName).size(100));}privateListStringgetAggByName(Aggregationsaggregations,StringaggName){// 4.1.根据聚合名称获取聚合结果TermsbrandTermsaggregations.get(aggName);// 4.2.获取bucketsList?extendsTerms.BucketbucketsbrandTerms.getBuckets();// 4.3.遍历ListStringbrandListnewArrayList();for(Terms.Bucketbucket:buckets){// 4.4.获取keyStringkeybucket.getKeyAsString();brandList.add(key);}returnbrandList;}本文的引用仅限自我学习如有侵权请联系作者删除。参考知识ElasticSearch (ES从入门到精通一篇就够了)ELK介绍