从零开始Java搜索引擎开发-ElasticSearch篇
这个系列的文章是博主自己从零开始学习ElasticSearch的记录。从最基础的单机服务、查询语句学习到集群模式、分词扩展、聚合统计等。争取实现垂直领域搜索引擎的基本应用,以及聚合功能在数据统计中的基本应用。
系列文章持续更新中......
  • 择其善而从之——我为什么开始学习ElasticSearch   

    人生天地之间,若白驹之过隙,忽然而已。 感慨刚毕业与同学合租打网游的场景仿佛还在眼前,现在参加工作都已经九年了,这时间流逝的速度一点不亚于“过隙白驹”啊!九年时间,我工作过三家公司,包括现在这家,三家公司的工作时间分别是一年、四年、4年。像我这个跳槽频率,应该可以算低了,特别是我们这一行。而且,其中有八年时间我都专注于Java领域的搜索引擎开发;往细节说,就是专注于垂直领域的基于Solr的搜索引擎开发。所以,在“Solr应用于垂直搜索”这个领域,我应该可以算得上专家了,至少时间上差不多够到专家门槛了。来现在这家公司之前,面试过几个公司,对我的技术和业务能力还算认可,不过他们都要求我转ElasticSearch。关于这个ES,我也是听说过,只是没用过。所以我问他们,为什么选这个框架而不是Solr(之所以这么问,有一部原因是我一直使用的Solr居然被人看不起)?是基于数据量考量还是基于功能考量。大部分人都没有颇具说服力的理由,主要的原因有以下几条:1. ElasticSearch 是一个分布式搜索引擎框架,分布式又是互联网热门词汇2. ElasticSearch 实时性比较好3. ElasticSearch 支持的数据量更大4. ElasticSearch 查询性能更高,尤其是大数据量的时候但是一问具体有测试报告或者自己做过测试没有,都说没有。问号脸???没有调查就么有发言权。当时针对这几个理由,我也无力反驳,谁叫我不懂ElasticSearch呢。----- 理性分析不过话说回来,为什么我遇到的公司的技术负责人选技术这么随意呢?ElasticSearch 能搭上分布式的船就选它?分布式自带大数据属性,所以就是一个互联网公司了?而且部署了支持大数据的分布式搜索引擎的互联网公司?暂且不纠结是不是面试官不屑于跟我说明具体原因,下面让我来分析分析上面的几条原因。 分布式这没什么好说的,ElasticSearch天生就是分布式的。而Solr是以单机版出道的;后来出了Solr-cloud,需要手动维护节点;现在Solr也学习了ElasticSearch的优点,cloud版本就是天然分布式,部署和维护也更方便了。 实时性这是Lucene的能力,而不是ElasticSearch或者Solr的。在我的知识范畴里面,Lucene(4.7.2)本身是没有索引更新能力的,都是先删除再插入,这应该是跟倒排链表数据结构有关。官方文档这样说的: In either case, documents are added with addDocument and removed with deleteDocuments(Term) or deleteDocuments(Query). A document can be updated with updateDocument (which just deletes and then adds the entire document). When finished adding, deleting and updating documents, close should be called.要说实时性,必须先简单介绍下Lucene搜索工具包支持的能力和概念。 Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎 工具包 ,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。 Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene提供了一个简单却强大的应用程式接口,能够做全文 索引 和 查询 。 在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆。索引和查询就是全文搜索引擎两个最重要的组成模块,在Lucene中分别提供了IndexWriter和IndexReader两个类,让我们可以轻松实现这两个模块的读写。 IndexWriter它负责一个索引的创建和维护,所以它会打开一个(这里的一个指一个完整的索引包含的全部索引文件,而不是单独一个索引文件)已有的索引文件,或者创建一个新的索引。具体有三种模式、创建(CREATE)、更新(APPEND)、创建或更新(CREATEORAPPEND),具体定义见枚举OpenMode(org.apache.lucene.index.IndexWriterConfig.OpenMode)。文档中还提到,创建一个IndexWriter(打开一个索引,就是将索引加载到内存)时会给索引文件目录创建一个lock文件,也就是上锁,此时如果尝试在同一个目录创建另一个IndexWriter对象时,将会抛LockObtainFailedException错。所以Solr配置多个Core的时候是分文件夹的。所以,IndexWriter负责的是将索引数据持久化到磁盘。 IndexReader这是一个虚拟类,有很多不同功能的子类,主要分为两大派系:AtomicReader和CompositeReader。看类名,应该就知道AtomicReader是负责对索引进行原子操作的类,负责访问实际索引文件内容的,比如存储的字段定义、文档值以及term信息。CompositeReader是一个复合类,会包含多个不同功能的Reader,进行组合使用,本身是不能直接访问索引文件内容的。比如,CompositeReader持有多个AtomicReader实例,通过这些AtomicReader实例来进行索引文件的读取。 Writer和Reader的关系当一个索引正在被IndexReader使用时,也可以同时被IndexWriter打开。不过IndexReader持有的索引版本是打开时的快照版本,如果此时IndexWriter对索引进行了更新(先删除再新增,下同),IndexReader也不会看到这部分更新的数据,除非IndexReader重新打开这个新的索引。所以,一个索引更新(IndexWriter写入)想马上被IndexReader发现(说通俗点就是被用户感知),就必须将索引文件重新加载到内存,而加载一次索引的开销非常大(IO开销),具体耗时由索引文件的大小决定。为了在加载索引文件过程中,系统还能提供查询服务,所以必须同时保持之前的IndexReader对象,直到新所以文件加载完成并替换掉旧的IndexReader对象。 IndexReader支持实时性简单说说第一种情况,称为过程A:1. 初始化加载索引文件,生成一个IndexReader对象记为R12. 此时发生数据更新,那么先生成一个IndexWrter对象,记为W1,然后由W1进行数据更新操作(如果是需要删除的话,会同步从R1中进行删除),生成新的索引文件3. 系统重新加载索引文件,包含刚刚W1生成的新文件,记为R2;在R2完全加载成功之前,内存中必须同时存在R1和R2,由R1继续提供查询服务4. 当R2加载成功,则会替换掉R1,向外提供查询服务,那么此时对于用户来说就能感知到W1更新的数据了不过过程A有个很大的问题就是,如果R2加载时间比较长,那么从W1更新数据到R2加载完成并替换掉R1的这段时间内,用户依旧感知不到数据更新,那么就谈不上实时性了,所以有了过程B:1. 初始化加载索引文件,生成一个IndexReader对象记为R12. 此时发生数据更新,那么先生成一个IndexWrter对象,记为W1,然后由W1进行数据更新操作,生成新的索引文件3. 同时在内存中生成一个只包含更新数据的R2,后续新增的数据都会同步在R2中进行维护。此时由R1和R2共同向外提供查询服务,两者的并集就是完整的数据4. 系统重新加载完整的索引文件,包含刚刚W1生成的新文件,记为R3(内存中的R1和R2无法合并,必须通过重新加载)。在R3完全加载成功之前,内存中必须同时存在R1、R2和R3,且由R1和R1共同提供查询服务5. 当R3加载成功,则会替换掉R1,系统同时丢弃R2,最终R3向外提供查询服务,那么此时对于用户来说就能感知到W1更新的数据了整个过程B中,查询服务提供者变化是:R1 --- (R1 + R2) --- R3其中从R2+R1过度到R3的过程我们可以称之为“搜索预热”,内存占用率其实会很高,最高的情况将占用一个完整索引所占用内存的两倍大小。再极限的情况,如果上一个搜索预热过程没有完成,又发生了下一个预热,系统将会开始下一个搜索预热过程,依次循环。所以,内存中会有多个过程B存在,内存占用率可想而知。这就是近实时搜索(Near Real Time Search)的代价。 Solr中的实时性在Solr的solrconfig.xml配置文件中,就有一项针对近实时搜索内存占用率的参数配置:xml2这个参数值指的就是内存中同时存在过程B的数量上限,一旦超过就会报错,内存中丢失一部分数据,磁盘中的索引数据不受影响。关于Solr的实时搜索触发、配置、自动软提交、硬提交等内容,将会在另一篇文章中进行详细介绍。所以,ElasticSearch的实时性与Solr的实时性搜索是一样的,并没有优劣之分,它们都是继承自Lucene,而且代价都很大。 数据量更大分布式的ElasticSearch支持的数据量确实更大,毫无疑问。但这是相对于单机版Solr来说的,分布式Solr-cloud数据量也是一样的支持。我说一下个人的经验数据吧。在使用单机版Solr时,我目前达到的最大数据量在千万级,具体是960W,而且单索引占用内存的大小为40GB。所以,在千万级数据量且索引大小比较大的情况下,单机Solr完全能支持,而且搜索性能也是比较高。这一点,我在另一篇搜索文章[《搜索引擎入门——启动第一个Solr应用》](https://oomabc.com/articledetail?atclidf9b37293ec184ab6ad4d672327057dd7)中关于“关于版本的选择”章节有介绍。所以,根据应用场景的当前数据量以及未来可期的数据量,可以自行评估,进行合理的选择。毕竟单机Solr的可维护性是远远高于分布式版本的Solr和ElasticSearch的。 查询性能脱离场景和数据量谈性能就是耍流氓。 择其善者而从之作为开源搜索引擎的明星框架,ElasticSearch必须是尤其优势的地方。除了更方便的集群管理,它的管道(aggregate)数据统计功能是非常非常非常强大。注意,我用了三个非常。Solr的facet功能与之相比,简直小巫见大巫,不过场景不同,本身facet就是很消耗性能的一个功能。新版本Solr应该也有代替方案了。之前使用过MongoDB的group和aggregate功能,虽然也很好用,但是其性能是远远不及ElasticSearch的aggregate的。所以,我准备从零开始,学习下ElasticSearch的使用。学习方面主要有:+ 基础查询语法+ 统计aggregate功能+ 集群部署、管理和维护+ 分词器接入,词库动态加载+ 同义词模块---

    ElasticSearch   ES   Solr   搜索引擎   2019-10-12 浏览(273) 有用(0) 阅读原文>> [原创]
  • 搜索引擎入门——启动第一个ElasticSearch单机节点   

    地转天旋,万事开头难。 斗霜傲雪二十年,堂堂剑气尚寒。 戎马倥偬一生,多少失败成功? 试看大千世界,依旧海阔天空。其实吧,启动一个单机的Elasticsearch(下文称ES)节点,非常简单。之所以会有这么一首诗,完全是为了装,贱笑,贱笑了! Elasticsearch简介ES是应用非常广泛的分布式搜索引擎和分析引擎。著名的ELK中的E就是ES,L指的是Logstah,它用于收集数据(日志),K指的是Kibana,它是一个可视化的操作和分析工具。ES可以为几乎所有类型的数据提供实时搜索和分析功能。无论是结构化数据、非结构化数据、数值型数据、甚至是空间地理数据,ES都能以支持快速搜索为前提,有效的对其进行存储和索引。通过它,我们不进行可以进行快速搜索,还能通过聚合、统计等功能来发现数据中隐藏的趋势。ES的分布式特性可以很轻松的进行集群扩展,以解决数据量和查询量快速增长带来的问题。ES解决的不仅仅是搜索的问题:+ 给我们的网址添加一个搜索框,当然这解决的是基础的搜索问题+ 储存和分析海量数据,比如访问日志、性能指标或其它案例数据+ 可以实时的通过机器学习为用户行为数据进行建模+ 作为业务上自动化工作流的存储引擎+ 作为空间地理信息管理系统(GIS),为空间数据进行管理、集成和分析+ 为其它场景的海量数据查询、分析提供基本能力使用ES的场景千变万化,但是其基本的索引和查询方式都是一样的。 数据输入作为一个分布式的文档存储引擎,ES不会按行(一行包含多列)来存储数据,取而代之的是更为复杂的且序列化过的JSON文本。如果你运行的是一个多节的ES集群,那么索引数据将会分布在各个节点,而且可以通过任意节点访问到所有数据。 为什么这里是JSON,应该是ES进行了封装,屏蔽了Lucene层面的Document和Field的概念,最底层还是这些。当提交一个新的文档到ES存储时,几乎可以在一秒内就搜索到这个数据,所以是准实时的。ES的索引结构和Solr一样,都是倒排索引结构。关于倒排索引的简单结构和功能,可以参考另两篇文章[《搜索引擎入门——什么是中文分词以及它对于搜索引擎的意义》](https://oomabc.com/articledetail?atclid9500e8e3135b42709439f98780427f8a)和[搜索引擎进阶——Lucene链表操作解析 ](https://oomabc.com/articledetail?atclida44bc93b559148e8a30b5a372f632ba3)。虽然ES具有无模式能力,它能自动根据提交的文档中的字段来识别数据类型并选择最优数据结构对其进行索引。官方还是建议针对同一个字段统一数据类型,或者通过规则进行动态映射:+ 区分全文的字符串字段和精确数值字符串字段+ 根据不同数据类型进行特殊的文本分析+ 跨类型的匹配性能会有所降低+ 可以使用系统无法检测的数据类型,主要是空间地理位置的信息,比如经纬度值,包括坐标和范围+ 可以使用其他的自定义数据类型 信息输出基于Lucene,ES让我们可以轻松使用搜索引擎的完整功能。ES提供了一套简单的、标准的REST接口,用于管理数据与集群。同时也提供了多种开发语言的工具包,Java、JavaScript、Go、.NET、PHP、Perl、Python、Ruby。 搜索数据ES的REST接口支持结构化查询、全文的文本查询以及复合查询。结构化查询:JSON{ "query" : { "match" : { "cityId" : 30201 } }, "sort" : [ { "annualSalary" : "desc"} ], "from" : 0, "size" : 20, "source" : ["title", "id", "cityId", "location", "annualSalary", "companyId"]}全文查询,指定关键字进行匹配,然后根据匹配度进行排序:JSON{ "query" : { "match" : { "title" : "java 产品经理" } }, "from" : 0, "size" : 20} 分析数据除了搜索,还可以使用ES中极其极其强大的聚合功能——aggregate。通过聚合,不仅可以实现大海捞针的目的,还能得到:+ 有多少根针+ 针的平均长度是多少+ 针的长度中位数是多少,制造商统计+ 在过去六个月中,每个月分别有多少针掉到海里更细致的功能还有:+ 制造最多针的制造商排名+ 最长针排名统计,以及各自段位内的制造商排名聚合利用了搜索引擎的倒排索引结构,因此性能非常高。而且本身搜索和聚合是可以同时使用的,这意味着我们可以根据搜索条件定位一批数据,然后基于这一批数据进行实时聚合。 启动单机节点 下载Linux/MaxOS版本bashwget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.4.0-darwin-x8664.tar.gzwget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.4.0-darwin-x8664.tar.gz.sha512shasum -a 512 -c elasticsearch-7.4.0-darwin-x8664.tar.gz.sha512 1tar -xzf elasticsearch-7.4.0-darwin-x8664.tar.gzcd elasticsearch-7.4.0/ 2 1:主要是为了对比下载的压缩包的SHA值与发布版本的验证值是否一致,正确的输出是:elasticsearch-{version}-darwin-x8664.tar.gz: OK。 2:解压之后的根目录。 启动bash./bin/elasticsearch 以后台方式启动bash./bin/elasticsearch -d -p pid-d表示后台方式运行,-p将会输出进程ID。 停止bashpkill -F pid 访问启动成功之后就可以正常访问ES节点了,访问地址http://localhost:9200/,可以打开一个页面,显示了节点的基本信息:JSON// 20191017194619// http://localhost:9200/{ "name": "wjyuianMacBookPro", "clustername": "elasticsearch", "clusteruuid": "yENYxaBTRKSI41NyVmo5w", "version": { "number": "7.3.1", "buildflavor": "default", "buildtype": "tar", "buildhash": "4749ba6", "builddate": "2019-08-19T20:19:25.651794Z", "buildsnapshot": false, "luceneversion": "8.1.0", "minimumwirecompatibilityversion": "6.8.0", "minimumindexcompatibilityversion": "6.0.0-beta1" }, "tagline": "You Know, for Search"}

    搜索引擎   ES   ElasticSearch   2019-10-28 浏览(239) 有用(0) 阅读原文>> [原创]
  • 搜索引擎入门——ElasticSearch的基本查询   

    快速预览不管处于什么年龄阶段,我个人在学习新事物的时候总会有一个迫切的诉求,那就是希望新事物能以旧方式呈现。所以,我也希望在搭建好ElasticSearch之后,它能像其它数据存储引擎一样,让我快速的进行数据的预览、查询、新增。不知道是不是我的思想过于陈旧了,总觉得熟悉的面貌能让我快速进入角色,开始学习。好在我也找到了一款Chrome插件,让我们对ElasticSearch数据进行预览等操作。![图片](https://oomabc.com/staticsrc/img/201910/28/15722296647314c5ee3921d514ec5adb1f11d0477d175.jpg) Dejavu The Missing Data Browser and Web UI for Elasticsearch.它是一款ElasticSearch专用的浏览器插件,支持ES的查询、数据导入、语句分析等功能:+ 导入数据的方式支持在线JSON,JSON文件、CSV文件+ 在线进行数据查询、过滤、数据统计+ 进行数据的CRUD操作![blockimg](https://oomabc.com/staticsrc/img/201910/28/157222969364193b245fadd104a179943e05659981aab.jpg)上图就是插件打开之后的主页面,需要输入ES的地址,以及我们需要预览的index的名称,这里是position,截图中的数据都是在我通过json文件导入之后的。当然,我们可以使用官方推荐的Kibana。 Import Data![blockimg](https://oomabc.com/staticsrc/img/201910/28/15722299661141f3137807f8b4d109c22755bfc80af6d.jpg)点击Upload File按钮边上的问号,可以看下格式说明。简单来说,Json格式就是一个Java对象的Json字符串。准备好文件直接上传就行了,不过建议文件大小不要过大,几十兆就行了,否则浏览器容易卡死。其它功能,我也没做过多的使用,这里就不展开介绍了,大伙自己个儿去试试看吧。 查询SearchElasticSearch提供的RESTful风格的接口,通用查询路径是${host:port}/名称/search,查询参数都是以json格式提交,所以要求我们将查询语句设置在request的body中,所以同时要设置Headers的Content-Type为application/json(默认的应该是text/plain)。后续的测试用例,都是通过Postman来发送请求,请求的索引名称是之前导入数据的position索引。 matchall查询路径是http://localhost:9200/position/search;提交参数:JSON{ "query" : { "matchall" : { } }, "sort" : [ { "annualSalary" : "desc"} ], "from" : 2, "size" : 30, "source" : ["title", "id", "cityId", "location", "annualSalary", "companyId", "time"]}+ query:查询语句+ sort:排序字段,多个字段按照先后顺序生效+ from:类似mySQL的limit的first+ size:类似mySQL的limit的max,即本次返回条数+ source:返回字段,默认返回文档的所有字段返回结果:JSON{ "took": 2, "timedout": false, "shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 377, "relation": "eq" }, "maxscore": null, "hits": [ { "index": "position", "type": "doc", "id": "v1ZzGwB4dN2kRyBPbIL", "score": null, "source": { "annualSalary": "1000000", "edittime": "26/8/2019 09:58:45", "investigationtime": "26/8/2019 09:36:43", "modifytime": "26/8/2019 07:00:22", "cityId": "30201", "verifytime": "22/8/2019 10:22:53", "title": "商务战略总监", "guaranteetime": "6", "companyId": "71799", "publishtime": "22/8/2019 10:22:53", "keepcontacttime": "工作日", "location": "上海 上海 上海市徐汇区宜山路711号华鑫商务中心2号楼游族大厦", "id": "127029", "statustime": "26/8/2019 09:36:43" }, "sort": [ 1000000 ] } ] }}简单介绍下返回结果的字段,相信大家自己也能看得懂:+ took:本次请求所消耗的时间,单位:毫秒+ timeout:请求是否超时+ shards:主要针对集群模式;本次搜索涉及了几个分片,以及分片的状态统计,比如成功、失败、跳过+ hits.maxscore:与查询条件相关度最大的文档的得分;上面的例子中通过查询参数sort进行排序配置,所以这一项值是null+ hits.total.value:总结果数+ hits.hits.sort:文档参与排序的排序值,查询参数设置了sort值,才会有这一项+ hits.hits.score:文档对应的排序值;matchall时也会有值,单此时不具备参考意义 match/matchphrase上面提到的matchall类似于Solr中的q:,就是匹配所有文档,没什么具体意义。如果需要匹配具体字段,那么就需要用到match了,例如:JSON{ "query" : { "match" : { "title":"java 上海"} }}上面的查询条件将会返回title中包含java或者上海的所有文档,也就是说match条件下默认是分词结果或的匹配逻辑,所以中间有没有空格并不影响。如果我们需要的是且而不是或的匹配,那么将match换为matchphrase即可:JSON{ "query" : { "matchphrase" : { "title":"T56 java"} }}只是,这里必须是完全匹配,中间有没有空格,空格前后关键词的顺序都是有影响的。其实就是将T56 java作为一个完整的词进行匹配(phrase就是短语的意思),不过大小写不敏感。 bool/filter很简单,这是用来支持更复杂的查询逻辑的,类似mySQL的AND、OR的组合体:JSON{ "query" : { "bool" : { "must" : [ { "match" : { "title" : "专场" } }, { "match" : { "title" : "工程师" } } ], "mustnot" : [ { "match" : { "title" : "北京" } } ], "filter" : { "range" : { "annualSalary" : { "gte" : 400000, "lte" : 600000 } } } } }}同样的,match中的关键字是会进行分词,而且包含单字的词。比如专场关键词,将会搜出所有包含专场、专、场三个词中至少一个词的文档。must、should的查询语句会影响文档的得分。但是musthot与filter类似,只负责过滤(yes or no),不会对结果的得分产生影响。 Query DSL(Domain Specific Language)ElasticSearch定义了一套完整的基于json格式的查询语句语法,json格式的查询语句最终会生成一棵对应的查询树AST (Abstract Syntax Tree) ,树上有两种节点:+ 叶子节点:实际上指定了那个字段应该是哪个值,比如前面提到的match、range,还有基于分词的term等。+ 非叶子节点:包含若干个叶子节点、非叶子节点,也就是一个复合查询。比如上面提到的bool就是一个很典型的复合查询,还有后面将会介绍的dismax。 相关性得分文档的排序是根据其得分值来的,每个文档返回时都会包含一个元数据字段score。所以根据能否对文档的得分产生影响,将查询文本分为两类:Query和Filter,即查询和过滤,上面提到过的must、should属于Query context,而musthot与filter则属于Filter context。比如下面这段查询语句:JSON{ "query" : { "bool" : { "must" : [ { "match" : { "title" : "java" } }, { "match" : { "title" : "工程师" } } ], "mustnot" : [ { "match" : { "title" : "北京" } } ], "filter" : [ { "term" : { "cityId" : "30201" } } ] } }, "from" : 2, "size" : 30, "source" : ["title", "id", "cityId", "location", "annualSalary", "companyId", "time"]}注意1. 无论是Elasticsearch还是Solr,其得分值都是单精度的浮点型;因此所有实际的得分值精度超过其范围的,都将会被转为float而丢失精度。2. 我们只将那些希望对排序产生影响的查询语句放置在Query context中,而将其它都放置在Filter context中。这样能提高查询性能,并充分利用缓存。 复合查询(非叶子节点)既然是树形查询语句,那么非叶子节点下当然可以是叶子节点,或者其他非叶子节点了。所以复合查询就是基础查询或其他复合查询的组合体,它会将其包含的子查询的结果进行合并、得分进行综合,亦或是仅仅将Query context转为Filter context。参考文档[《Compound queries》](https://www.elastic.co/guide/en/elasticsearch/reference/current/compound-queries.html)。 bool查询它可以将基础查询或者其它复合查询进行组合,包含must、should、mustnot和filter。其中,must、should属于Query context,会影响文档得分;而musthot与filter则属于Filter context,不会影响文档得分。 boosting查询JSON{ "query" : { "boosting" : { "positive" : { "match" : { "title" : "java" } }, "negative" : { "matchphrase" : { "title" : "专家" } }, "negativeboost": 0.2 } }, "from" : 0, "size" : 30, "source" : ["title"]}+ positive:必填,所有返回文档都满足这个查询条件+ negative:必填,如果返回文档同时满足这个条件,则会重新计算得分: 1. 获取positive的初始得分 2. 将初始得分乘以negativeboost值作为该文档的最后得分+ negativeboost:必填,当返回文档满足negative条件时,文档得分会被乘以这个值,这个值必须在0~1之间。 constantscore查询JSON{ "query" : { "constantscore" : { "filter" : { "match" : { "title" : "java" } }, "boost" : 2 } }, "from" : 0, "size" : 30, "source" : ["title"]}所有符合filter条件的文档,其得分都是boost指定值,默认是1。 dismax查询JSON{ "query": { "dismax" : { "queries" : [ { "term" : { "title" : "java" } }, { "term" : { "cityId" : "30101" } }, { "term" : { "cityId" : "33102" } }, { "term" : { "location" : "北京" } } ], "tiebreaker" : 0.5 } }, "from" : 0, "size" : 30, "source" : ["title", "cityId", "location"]}+ queries:必填,是一个数组,数组里面是独立的查询语句,可以是复合的(也就是本节提到的所有复合查询),也可以是基础的。Elasticsearch会返回满足数组中任意一个查询条件的文档,如果有文档同时满足多条语句,则会使用分数最高的值作为最终得分,记为highestScore。+ tiebreaker:可选,范围是0到1。如果文档满足了多条语句,则除去得分最高的语句,系统会将剩余的匹配语句对应的得分都乘以该值tiebreaker。最后将highestScore与前面的乘积得分相加,最终值作为score返回。所以,tiebreaker为0时,最终得分就是得分最高的查询语句的得分;tiebreaker不为0时,所有匹配语句都会对得分产生正面影响,不过影响最大的还是得分最高的那条语句。 functionscore查询这一节比较复杂,将会另开一篇文章进行阐述。 待分析问题+ 多种复合查询之间如何复合+ match、matchphrase、term等各种匹配之间的异同----

    搜索引擎   ES   ElasticSearch   2019-10-29 浏览(242) 有用(0) 阅读原文>> [原创]
  • blogTest
    分享文章
     
    使用APP的"扫一扫"功能,扫描左边的二维码,即可将网页分享给别人。
    你也可以扫描右边本博客的小程序二维码,实时关注最新文章。