当前位置: 首页 > news >正文

网站建设与维护教学计划公司图标设计大全免费 logo

网站建设与维护教学计划,公司图标设计大全免费 logo,网站关键词如何优化,搭建网站一般要多少钱技术原理 索引文档 索引文档分为单个文档和多个文档。 单个文档 新建单个文档所需要的步骤顺序#xff1a; 客户端向 Node 1 发送新建、索引或者删除请求。节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3#xff0c;因为分片 0 的主分片目前被分配在 …技术原理 索引文档 索引文档分为单个文档和多个文档。 单个文档 新建单个文档所需要的步骤顺序 客户端向 Node 1 发送新建、索引或者删除请求。节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3因为分片 0 的主分片目前被分配在 Node 3 上。Node 3 在主分片上面执行请求。如果成功了它将请求并行转发到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都报告成功, Node 3 将向协调节点报告成功协调节点向客户端报告成功。 多个文档 使用 bulk 修改多个文档步骤顺序 客户端向 Node 1 发送 bulk 请求。Node 1 为每个节点创建一个批量请求并将这些请求并行转发到每个包含主分片的节点主机。主分片一个接一个按顺序执行每个操作。当每个操作成功时主分片并行转发新文档或删除到副本分片然后执行下一个操作。 一旦所有的副本分片报告所有操作成功该节点将向协调节点报告成功协调节点将这些响应收集整理并返回给客户端。 索引文档的实现机制 写操作的关键点 在考虑或分析一个分布式系统的写操作时一般需要从下面几个方面考虑 可靠性或者是持久性数据写入系统成功后数据不会被回滚或丢失。一致性数据写入成功后再次查询时必须能保证读取到最新版本的数据不能读取到旧数据。原子性一个写入或者更新操作要么完全成功要么完全失败不允许出现中间状态。隔离性多个写入操作相互不影响。实时性写入后是否可以立即被查询到。性能写入性能吞吐量到底怎么样。 Elasticsearch作为分布式系统通过如何保证的呢 可靠性由于Lucene的设计中不考虑可靠性在Elasticsearch中通过Replica和TransLog两套机制保证数据的可靠性。一致性Lucene中的Flush锁只保证Update接口里面Delete和Add中间不会Flush但是Add完成后仍然有可能立即发生Flush导致Segment可读。这样就没法保证Primary和所有其他Replica可以同一时间Flush就会出现查询不稳定的情况这里只能实现最终一致性。原子性Add和Delete都是直接调用Lucene的接口是原子的。当部分更新时使用Version和锁保证更新是原子的。隔离性仍然采用Version和局部锁来保证更新的是特定版本的数据。实时性使用定期Refresh Segment到内存并且Reopen Segment方式保证搜索可以在较短时间比如1秒内被搜索到。通过将未刷新到磁盘数据记入TransLog保证对未提交数据可以通过ID实时访问到。性能性能是一个系统性工程所有环节都要考虑对性能的影响在Elasticsearch中在很多地方的设计都考虑到了性能一是不需要所有Replica都返回后才能返回给用户只需要返回特定数目的就行二是生成的Segment现在内存中提供服务等一段时间后才刷新到磁盘Segment在内存这段时间的可靠性由TransLog保证三是TransLog可以配置为周期性的Flush但这个会给可靠性带来伤害四是每个线程持有一个Segment多线程时相互不影响相互独立性能更好五是系统的写入流程对版本依赖较重读取频率较高因此采用了versionMap减少热点数据的多次磁盘IO开销。Lucene中针对性能做了大量的优化。 Elasticsearch的写 Elasticsearch采用多Shard方式通过配置routing规则将数据分成多个数据子集每个数据子集提供独立的索引和搜索功能。当写入文档的时候根据routing规则将文档发送给特定Shard中建立索引。这样就能实现分布式了。 此外Elasticsearch整体架构上采用了一主多副的方式 每个Index由多个Shard组成每个Shard有一个主节点和多个副本节点副本个数可配。但每次写入的时候写入请求会先根据_routing规则选择发给哪个ShardIndex Request中可以设置使用哪个Filed的值作为路由参数如果没有设置则使用Mapping中的配置如果mapping中也没有配置则使用_id作为路由参数然后通过_routing的Hash值选择出Shard在OperationRouting类中最后从集群的Meta中找出出该Shard的Primary节点。 请求接着会发送给Primary Shard在Primary Shard上执行成功后再从Primary Shard上将请求同时发送给多个Replica Shard请求在多个Replica Shard上执行成功并返回给Primary Shard后写入请求执行成功返回结果给客户端。 这种模式下写入操作的延时就等于latency Latency(Primary Write) Max(Replicas Write)。只要有副本在写入延时最小也是两次单Shard的写入时延总和写入效率会较低但是这样的好处也很明显避免写入后单机或磁盘故障导致数据丢失在数据重要性和性能方面一般都是优先选择数据除非一些允许丢数据的特殊场景。 采用多个副本后避免了单机或磁盘故障发生时对已经持久化后的数据造成损害但是Elasticsearch里为了减少磁盘IO保证读写性能一般是每隔一段时间比如5分钟才会把Lucene的Segment写入磁盘持久化对于写入内存但还未Flush到磁盘的Lucene数据如果发生机器宕机或者掉电那么内存中的数据也会丢失这时候如何保证 对于这种问题Elasticsearch学习了数据库中的处理方式增加CommitLog模块Elasticsearch中叫TransLog。 在每一个Shard中写入流程分为两部分先写入Lucene再写入TransLog。 写入请求到达Shard后先写Lucene文件创建好索引此时索引还在内存里面接着去写TransLog写完TransLog后刷新TransLog数据到磁盘上写磁盘成功后请求返回给用户。这里有几个关键点: 一是和数据库不同数据库是先写CommitLog然后再写内存而Elasticsearch是先写内存最后才写TransLog一种可能的原因是Lucene的内存写入会有很复杂的逻辑很容易失败比如分词字段长度超过限制等比较重为了避免TransLog中有大量无效记录减少recover的复杂度和提高速度所以就把写Lucene放在了最前面。二是写Lucene内存后并不是可被搜索的需要通过Refresh把内存的对象转成完整的Segment后然后再次reopen后才能被搜索一般这个时间设置为1秒钟导致写入Elasticsearch的文档最快要1秒钟才可被从搜索到所以Elasticsearch在搜索方面是NRTNear Real Time近实时的系统。三是当Elasticsearch作为NoSQL数据库时查询方式是GetById这种查询可以直接从TransLog中查询这时候就成了RTReal Time实时系统。四是每隔一段比较长的时间比如30分钟后Lucene会把内存中生成的新Segment刷新到磁盘上刷新后索引文件已经持久化了历史的TransLog就没用了会清空掉旧的TransLog。 数据更新 Update流程 Lucene中不支持部分字段的Update所以需要在Elasticsearch中实现该功能具体流程如下 收到Update请求后从Segment或者TransLog中读取同id的完整Doc记录版本号为V1。将版本V1的全量Doc和请求中的部分字段Doc合并为一个完整的Doc同时更新内存中的VersionMap。获取到完整Doc后Update请求就变成了Index请求。 加锁。再次从VersionMap中读取该id的最大版本号V2如果VersionMap中没有则从Segment或者TransLog中读取这里基本都会从VersionMap中获取到。 检查版本是否冲突(V1V2)如果冲突则回退到开始的“Update doc”阶段重新执行。如果不冲突则执行最新的Add请求。在Index Doc阶段首先将Version 1得到V3再将Doc加入到Lucene中去Lucene中会先删同id下的已存在doc id然后再增加新Doc。写入Lucene成功后将当前V3更新到VersionMap中。释放锁部分更新的流程就结束了。 查询文档 单个文档 从主分片或者副本分片检索文档的步骤顺序 客户端向 Node 1Master 发送获取请求。节点使用文档的 _id 来确定文档属于分片 0根据_routering确认文档所在的Shard 。分片 0 的副本分片存在于所有的三个节点上。 在这种情况下它将请求转发到 Node 2 。Node 2 将文档返回给 Node 1 然后将文档返回给客户端。 在处理读取请求时协调结点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。 在文档被检索时已经被索引的文档可能已经存在于主分片上但是还没有复制到副本分片。 在这种情况下副本分片可能会报告文档不存在但是主分片可能成功返回文档。 一旦索引请求成功返回给用户文档在主分片和副本分片都是可用的。 多个文档 使用 mget 取回多个文档的步骤顺序 使用单个 mget 请求取回多个文档所需的步骤顺序 客户端向 Node 1Master 发送 mget 请求。Node 1 为每个分片构建多文档获取请求然后并行转发这些请求到托管在每个所需的主分片或者副本分片的节点上。一旦收到所有答复 Node 1 构建响应并将其返回给客户端。 文档读取过程详解 所有的搜索系统一般都是两阶段查询 第一阶段查询到匹配的DocID第二阶段再查询DocID对应的完整文档这种在Elasticsearch中称为query_then_fetch。 除了一阶段两阶段外还有一种三阶段查询的情况。搜索里面有一种算分逻辑是根据TFTerm Frequency和DFDocument Frequency计算基础分但是Elasticsearch中查询的时候是在每个Shard中独立查询的每个Shard中的TF和DF也是独立的虽然在写入的时候通过_routing保证Doc分布均匀但是没法保证TF和DF均匀那么就有会导致局部的TF和DF不准的情况出现这个时候基于TF、DF的算分就不准。 为了解决这个问题Elasticsearch中引入了DFS查询比如DFS_query_then_fetch会先收集所有Shard中的TF和DF值然后将这些值带入请求中再次执行query_then_fetch这样算分的时候TF和DF就是准确的类似的有DFS_query_and_fetch。这种查询的优势是算分更加精准但是效率会变差。 另一种选择是用BM25代替TF/DF模型。 第一阶段 todo 第二阶段 在初始查询阶段时查询会广播到索引中每一个分片拷贝主分片或者副本分片。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from size 的优先队列。每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。接下来就是 取回阶段协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并丰富文档如果有需要的话接着返回文档给协调节点。一旦所有的文档都被取回了协调节点返回结果给客户端。 二阶段查询为例来介绍查询流程 Client Node 1.Get Remove Cluster Shard 判断是否需要跨集群访问如果需要则获取到要访问的Shard列表。 2.Get Search Shard Iterator 获取当前Cluster中要访问的Shard和上一步中的Remove Cluster Shard合并构建出最终要访问的完整Shard列表。 这一步中会根据Request请求中的参数从Primary Node和多个Replica Node中选择出一个要访问的Shard。 3.For Every Shard:Perform 遍历每个Shard对每个Shard执行后面逻辑。 4.Send Request To Query Shard 将查询阶段请求发送给相应的Shard。 5.Merge Docs 上一步将请求发送给多个Shard后这一步就是异步等待返回结果然后对结果合并。这里的合并策略是维护一个Top N大小的优先级队列每当收到一个shard的返回就把结果放入优先级队列做一次排序直到所有的Shard都返回。 翻页逻辑也是在这里如果需要取Top 30~ Top 40的结果这个的意思是所有Shard查询结果中的第30到40的结果那么在每个Shard中无法确定最终的结果每个Shard需要返回Top 40的结果给Client Node然后Client Node中在merge docs的时候计算出Top 40的结果最后再去除掉Top 30剩余的10个结果就是需要的Top 30~ Top 40的结果。 上述翻页逻辑有一个明显的缺点就是每次Shard返回的数据中包括了已经翻过的历史结果如果翻页很深则在这里需要排序的Docs会很多比如Shard有1000取第9990到10000的结果那么这次查询Shard总共需要返回1000 * 10000也就是一千万Doc这种情况很容易导致OOM。 另一种翻页方式是使用search_after这种方式会更轻量级如果每次只需要返回10条结构则每个Shard只需要返回search_after之后的10个结果即可返回的总数据量只是和Shard个数以及本次需要的个数有关和历史已读取的个数无关。这种方式更安全一些推荐使用这种。 如果有aggregate也会在这里做聚合但是不同的aggregate类型的merge策略不一样具体的可以在后面的aggregate文章中再介绍。 6.Send Request To Fetch Shard 选出Top N个Doc ID后发送给这些Doc ID所在的Shard执行Fetch Phase最后会返回Top N的Doc的内容。 Query Phase 接下来我们看第一阶段查询的步骤 1.Create Search Context 创建Search Context之后Search过程中的所有中间状态都会存在Context中这些状态总共有50多个具体可以查看DefaultSearchContext或者其他SearchContext的子类。 2.Parse Query 解析Query的Source将结果存入Search Context。这里会根据请求中Query类型的不同创建不同的Query对象比如TermQuery、FuzzyQuery等最终真正执行TermQuery、FuzzyQuery等语义的地方是在Lucene中。 这里包括了dfsPhase、queryPhase和fetchPhase三个阶段的preProcess部分只有queryPhase的preProcess中有执行逻辑其他两个都是空逻辑执行完preProcess后所有需要的参数都会设置完成。 由于Elasticsearch中有些请求之间是相互关联的并非独立的比如scroll请求所以这里同时会设置Context的生命周期。 同时会设置lowLevelCancellation是否打开这个参数是集群级别配置同时也能动态开关打开后会在后面执行时做更多的检测检测是否需要停止后续逻辑直接返回。 3.Get From Cache 判断请求是否允许被Cache如果允许则检查Cache中是否已经有结果如果有则直接读取Cache如果没有则继续执行后续步骤执行完后再将结果加入Cache。 4.Add Collectors Collector主要目标是收集查询结果实现排序对自定义结果集过滤和收集等。这一步会增加多个Collectors多个Collector组成一个List。 FilteredCollector先判断请求中是否有Post FilterPost Filter用于SearchAgg等结束后再次对结果做Filter希望Filter不影响Agg结果。如果有Post Filter则创建一个FilteredCollector加入Collector List中。PluginInMultiCollector判断请求中是否制定了自定义的一些Collector如果有则创建后加入Collector List。MinimumScoreCollector判断请求中是否制定了最小分数阈值如果指定了则创建MinimumScoreCollector加入Collector List中在后续收集结果时会过滤掉得分小于最小分数的Doc。EarlyTerminatingCollector判断请求中是否提前结束Doc的Seek如果是则创建EarlyTerminatingCollector加入Collector List中。在后续Seek和收集Doc的过程中当Seek的Doc数达到Early Terminating后会停止Seek后续倒排链。CancellableCollector判断当前操作是否可以被中断结束比如是否已经超时等如果是会抛出一个TaskCancelledException异常。该功能一般用来提前结束较长的查询请求可以用来保护系统。EarlyTerminatingSortingCollector如果Index是排序的那么可以提前结束对倒排链的Seek相当于在一个排序递减链表上返回最大的N个值只需要直接返回前N个值就可以了。这个Collector会加到Collector List的头部。EarlyTerminatingSorting和EarlyTerminating的区别是EarlyTerminatingSorting是一种对结果无损伤的优化而EarlyTerminating是有损的人为掐断执行的优化。TopDocsCollector这个是最核心的Top N结果选择器会加入到Collector List的头部。TopScoreDocCollector和TopFieldCollector都是TopDocsCollector的子类TopScoreDocCollector会按照固定的方式算分排序会按照分数doc id的方式排列如果多个doc的分数一样先选择doc id小的文档。而TopFieldCollector则是根据用户指定的Field的值排序。 5.lucene::search 这一步会调用Lucene中IndexSearch的search接口执行真正的搜索逻辑。每个Shard中会有多个Segment每个Segment对应一个LeafReaderContext这里会遍历每个Segment到每个Segment中去Search结果然后计算分数。 搜索里面一般有两阶段算分第一阶段是在这里算的会对每个Seek到的Doc都计算分数为了减少CPU消耗一般是算一个基本分数。这一阶段完成后会有个排序。然后在第二阶段再对Top 的结果做一次二阶段算分在二阶段算分的时候会考虑更多的因子。二阶段算分在后续操作中。 具体请求比如TermQuery、WildcardQuery的查询逻辑都在Lucene中后面会有专门文章介绍。 6.rescore 根据Request中是否包含rescore配置决定是否进行二阶段排序如果有则执行二阶段算分逻辑会考虑更多的算分因子。二阶段算分也是一种计算机中常见的多层设计是一种资源消耗和效率的折中。 Elasticsearch中支持配置多个Rescore这些rescore逻辑会顺序遍历执行。每个rescore内部会先按照请求参数window选择出Top window的doc然后对这些doc排序排完后再合并回原有的Top 结果顺序中。 7.suggest::execute() 如果有推荐请求则在这里执行推荐请求。如果请求中只包含了推荐的部分则很多地方可以优化。推荐不是今天的重点这里就不介绍了后面有机会再介绍。 8.aggregation::execute() 如果含有聚合统计请求则在这里执行。Elasticsearch中的aggregate的处理逻辑也类似于Search通过多个Collector来实现。在Client Node中也需要对aggregation做合并。aggregate逻辑更复杂一些就不在这里赘述了后面有需要就再单独开文章介绍。 上述逻辑都执行完成后如果当前查询请求只需要查询一个Shard那么会直接在当前Node执行Fetch Phase。 ExplainFetchSubPhaseDocValueFieldsFetchSubPhaseScriptFieldsFetchSubPhaseFetchSourceSubPhaseVersionFetchSubPhaseMatchedQueriesFetchSubPhaseHighlightPhaseParentFieldSubFetchPhase 除了系统默认的8种外还有通过插件的形式注册自定义的功能这些SubPhase中最重要的是Source和HighlightSource是加载原文Highlight是计算高亮显示的内容片断。 上述多个SubPhase会针对每个Doc顺序执行可能会产生多次的随机IO这里会有一些优化方案但是都是针对特定场景的不具有通用性。 Fetch Phase执行完后整个查询流程就结束了。 Fetch Phase Elasticsearch作为搜索系统时或者任何搜索系统中除了Query阶段外还会有一个Fetch阶段这个Fetch阶段在数据库类系统中是没有的是搜索系统中额外增加的阶段。搜索系统中额外增加Fetch阶段的原因是搜索系统中数据分布导致的在搜索中数据通过routing分Shard的时候只能根据一个主字段值来决定但是查询的时候可能会根据其他非主字段查询那么这个时候所有Shard中都可能会存在相同非主字段值的Doc所以需要查询所有Shard才能不会出现结果遗漏。同时如果查询主字段那么这个时候就能直接定位到Shard就只需要查询特定Shard即可这个时候就类似于数据库系统了。另外数据库中的二级索引又是另外一种情况但类似于查主字段的情况这里就不多说了。 基于上述原因第一阶段查询的时候并不知道最终结果会在哪个Shard上所以每个Shard中管都需要查询完整结果比如需要Top 10那么每个Shard都需要查询当前Shard的所有数据找出当前Shard的Top 10然后返回给Client Node。如果有100个Shard那么就需要返回100 * 10 1000个结果而Fetch Doc内容的操作比较耗费IO和CPU如果在第一阶段就Fetch Doc那么这个资源开销就会非常大。所以一般是当Client Node选择出最终Top N的结果后再对最终的Top N读取Doc内容。通过增加一点网络开销而避免大量IO和CPU操作这个折中是非常划算的。 Fetch阶段的目的是通过DocID获取到用户需要的完整Doc内容。这些内容包括了DocValuesStoreSourceScript和Highlight等具体的功能点是在SearchModule中注册的系统默认注册的有 第三阶段 todo 使用相关性进行搜索 在进行相关性搜索前先了解下面问题 Lucene和EIasticsearch内部打分是如何运作的提升特定查询或字段的得分使用解释的API接口来理解词频、逆文档频率、相关性得分通过重新计算文档子集的得分来减少评分操作的性能影响使用function—score查询获取终极的打分能力字段数据的缓存以及它是如何影响实例的 文档的评分使用的是TF-IDF或者BM25。 其他评分算法 随机性分歧Divergencefromrandomness即DFR相似度基于信息的lnformation即IB相似度LMDirichIet相似度LMJeIinekMercer相似度。 ElasticSearch如何给文档评分 有两种配置评分 索引字段评分ElasticSearch配置评分 索引字段评分-使用内置评分算法 PUT /mall_user {mappings: {properties: {name: {type: text,similarity: BM25, fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }在字段similarity配置内置的评分算法。 索引字段评分-自定义算法 PUT /mall_user {settings: {similarity:{customSimilarity:{type:BM25,k1:1.2,b:0.75,discount_overlaps:false}}},mappings: {properties: {name: {type: text,similarity: customSimilarity, fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }在setting.similarity参数定义评分算法并且在字段的similarity指定自定义的评分算法。 BM25有3种主要的设置即k1、b和discount_overlaps: k1:k1控制对于得分而言词频词条出现在文档里的频繁程度或者是TF的重要性。b:b是介于0到1之间的数值它控制了文档篇幅对于得分的影响程度。discount_overlaps:discount_overlaps的设置告知Elasticsearch在某个字段中多个分词出现在同一个位置是否应该影响长度的标准化。默认值是true. 默认情况下k1被设置为1.2而b被设置为0.75。 如果希望全局修改评分算法在elasticsearch.yml配置文件中配置 index.similarity.default.type: BM25boosting boosting是一个可以用来修改文档的相关性的程序。 boosting有两种类型当索引或者查询文档的时候可以提升一篇文档的得分。在索引期间修改的文档boosting是存储在索引中的修改boosting值唯一的方法是重新索引这篇文档。鉴于此我们当然建议用户使用查询期间的boosting因为这样更为灵活并允许用户改变主意在不重新索引数据的前提下改变字段或者词条的重要性。 在索引期间boost文档是不推荐的。 1.在索引期间配置boost PUT /mall_user {mappings: {properties: {name: {type: text,boost: 3.0, fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }在设置该索引的映射后任何自动索引的文档就拥有一个boost值运用于name字段的词条中。再次强调一下请记住这个boost的值是固定的(fixed也就是说如果决定修改这个值你必须重新索引文档。 在索引期间boost文档是不推荐的原因 精度丢失boost的值是以低精度的数值存储在Lucene的内部索引结构中。只有一个字节用于存储浮点型数值所以计算文档的最终得分时可能会丢失精度。boost是运用于一个词条的。因此在被boost的字段中如果匹配上了多个词条就意味着多次的boost将会进一步增加字段的权重。 2.查询期间boosting 当进行搜索的时候有几种方法进行boosting。如果使用基本的match、multi_match、simple_query_string或query_string查询就可以基于每个词条或者每个字段来控制boost.几乎所有的Elasticsearch查询类型都支持boosting.如果这个还不够灵活那么可以通过function_score查询以更为精细的方式来控制boosting. 开始查询前先创建一个索引 PUT /mall_goods_test {mappings: {properties: {title: {type: text,fields: {raw: {type: keyword}}},attribute:{type:text},desc:{type:text},price:{type: double}}} }POST /mall_goods_test/_doc/1 {title:Apple iPhone 15 Pro Max - 全新旗舰智能手机,attribute:256GB Pro,desc:iPhone 15 Pro Max采用了全新的设计语言机身采用航空级铝合金打造正面是一块6.7英寸的超视网膜XDR显示屏分辨率高达4K显示效果惊艳。同时这款手机还支持120Hz的高刷新率让您在浏览网页、玩游戏时更加流畅。,price: 4999 }POST /mall_goods_test/_doc/2 {title:Apple iPhone 15 Pro Max - 全新旗舰智能手机,attribute:512GB Pro Max,desc:iPhone 15 Pro Max采用了全新的设计语言机身采用航空级铝合金打造正面是一块6.7英寸的超视网膜XDR显示屏分辨率高达4K显示效果惊艳。同时这款手机还支持120Hz的高刷新率让您在浏览网页、玩游戏时更加流畅。,price: 6999 }POST /mall_goods_test/_doc/3 {title:Apple iPhone 15 Pro Max - 全新旗舰智能手机,attribute:1TB Pro Max,desc:iPhone 15 Pro Max采用了全新的设计语言机身采用航空级铝合金打造正面是一块6.7英寸的超视网膜XDR显示屏分辨率高达4K显示效果惊艳。同时这款手机还支持120Hz的高刷新率让您在浏览网页、玩游戏时更加流畅。,price: 12999 }match查询 POST /mall_goods_test/_search {query: {bool: {should:[{match: {title: iPhone 1TB}},{match: {attribute: {query: iPhone 1TB,boost: 3.0}}}]}} }增加boost参数默认1.0。在搜索中我们认为attribute 的描述更加符合搜索的需求通过设置boost参数实现。 当使用bool或and/or/not组合多个查询时boost查询才有意义。 multi_match查询 multi_match和match类似多个字段指定同一个boost值。 POST /mall_goods_test/_search {query: {multi_match: {query: iPhone 1TB,fields: [title,attribute],boost: 3.0}} }或者使用^为各个字段指定boost值 POST /mall_goods_test/_search {query: {multi_match: {query: iPhone 1TB,fields: [title^0.75,attribute^3]}} }title设置boost为0.75 attribute设置boost为3 query_string 查询 match、multi_match查询是为字段指定boost值query_string可以为搜索文本中的某个词设置boost。 POST /mall_goods_test/_search {query: {query_string: {query: iPhone 256GB^3}} }认为256比iPhone关键词相关性更加高为256设置更高的boost。 explain查看评分的详细信息 POST /mall_goods_test/_search {query: {query_string: {query: iPhone 256GB^3}},explain: true }256GB boost对评分的贡献比较大。 _explain查看为何没有匹配文档 POST /mall_goods_test/_doc/1/_explain {query:{match: {title: Huawei}} }输出 {_index : mall_goods_test,_type : _doc,_id : 1,matched : false,explanation : {value : 0.0,description : no matching term,details : [ ]} }查看_id1的文档为何没有匹配“Huawei”从结果明显看出是不匹配。 function_score 打分更加自由的打分。todo Elasticsearch Function Score 1.Lucene和EIasticsearch内部打分是如何运作的 确定文档和查询相关程度的过程被称为打分scoring。 Bulk请求 Elasticsearch写入请求类型 Elasticsearch中的写入请求类型主要包括下列几个Index(Create)UpdateDelete和Bulk其中前3个是单文档操作后一个Bulk是多文档操作其中Bulk中可以包括Index(Create)Update和Delete。 在6.0.0及其之后的版本中前3个单文档操作的实现基本都和Bulk操作一致甚至有些就是通过调用Bulk的接口实现的。估计接下来几个版本后Index(Create)UpdateDelete都会被当做Bulk的一种特例化操作被处理。这样代码和逻辑都会更清晰一些。 下面我们就以Bulk请求为例来介绍写入流程。 红色Client Node。 绿色Primary Node。 蓝色Replica Node。 Client Node 1.Ingest Pipeline 在这一步可以对原始文档做一些处理比如HTML解析自定义的处理具体处理逻辑可以通过插件来实现。在Elasticsearch中由于Ingest Pipeline会比较耗费CPU等资源可以设置专门的Ingest Node专门用来处理Ingest Pipeline逻辑。 如果当前Node不能执行Ingest Pipeline则会将请求发给另一台可以执行Ingest Pipeline的Node。 2.Auto Create Index 判断当前Index是否存在如果不存在则需要自动创建Index这里需要和Master交互。也可以通过配置关闭自动创建Index的功能。 3.Set Routing 设置路由条件如果Request中指定了路由条件则直接使用Request中的Routing否则使用Mapping中配置的如果Mapping中无配置则使用默认的_id字段值。 在这一步中如果没有指定id字段则会自动生成一个唯一的_id字段目前使用的是UUID。 4.Construct BulkShardRequest 由于Bulk Request中会包括多个(Index/Update/Delete)请求这些请求根据routing可能会落在多个Shard上执行这一步会按Shard挑拣Single Write Request同一个Shard中的请求聚集在一起构建BulkShardRequest每个BulkShardRequest对应一个Shard。 5.Send Request To Primary 这一步会将每一个BulkShardRequest请求发送给相应Shard的Primary Node。 Primary Node Primary 请求的入口是在PrimaryOperationTransportHandler的messageReceived. 1.Index or Update or Delete 循环执行每个Single Write Request对于每个Request根据操作类型(CREATE/INDEX/UPDATE/DELETE)选择不同的处理逻辑。 其中Create/Index是直接新增DocDelete是直接根据_id删除DocUpdate会稍微复杂些我们下面就以Update为例来介绍。 2.Translate Update To Index or Delete 这一步是Update操作的特有步骤在这里会将Update请求转换为Index或者Delete请求。首先会通过GetRequest查询到已经存在的同_id Doc如果有的完整字段和值依赖_source字段然后和请求中的Doc合并。同时这里会获取到读到的Doc版本号记做V1。 3.Parse Doc 这里会解析Doc中各个字段。生成ParsedDocument对象同时会生成uid Term。在Elasticsearch中_uid type # _id对用户_Id可见而Elasticsearch中存储的是_uid。这一部分生成的ParsedDocument中也有Elasticsearch的系统字段大部分会根据当前内容填充部分未知的会在后面继续填充ParsedDocument。 4.Update Mapping Elasticsearch中有个自动更新Mapping的功能就在这一步生效。会先挑选出Mapping中未包含的新Field然后判断是否运行自动更新Mapping如果允许则更新Mapping。 5.Get Sequence Id and Version 由于当前是Primary Shard则会从SequenceNumber Service获取一个sequenceID和Version。SequenceID在Shard级别每次递增1SequenceID在写入Doc成功后会用来初始化LocalCheckpoint。Version则是根据当前Doc的最大Version递增1。 6.Add Doc To Lucene 这一步开始的时候会给特定_uid加锁然后判断该_uid对应的Version是否等于之前Translate Update To Index步骤里获取到的Version如果不相等则说明刚才读取Doc后该Doc发生了变化出现了版本冲突这时候会抛出一个VersionConflict的异常该异常会在Primary Node最开始处捕获重新从“Translate Update To Index or Delete”开始执行。 如果Version相等则继续执行如果已经存在同id的Doc则会调用Lucene的UpdateDocument(uid, doc)接口先根据uid删除Doc然后再Index新Doc。如果是首次写入则直接调用Lucene的AddDocument接口完成Doc的IndexAddDocument也是通过UpdateDocument实现。 这一步中有个问题是如何保证Delete-Then-Add的原子性怎么避免中间状态时被Refresh答案是在开始Delete之前会加一个Refresh Lock禁止被Refresh只有等Add完后释放了Refresh Lock后才能被Refresh这样就保证了Delete-Then-Add的原子性。 Lucene的UpdateDocument接口中就只是处理多个Field会遍历每个Field逐个处理处理顺序是invert indexstore fielddoc valuespoint dimension后续会有文章专门介绍Lucene中的写入。 7.Write Translog 写完Lucene的Segment后会以key-value的形式写TransLogKey是_idValue是Doc内容。当查询的时候如果请求是GetDocByID则可以直接根据_id从TransLog中读取到满足NoSQL场景下的实时性要去。 需要注意的是这里只是写入到内存的TransLog是否Sync到磁盘的逻辑还在后面。 这一步的最后会标记当前SequenceID已经成功执行接着会更新当前Shard的LocalCheckPoint。 8.Renew Bulk Request 这里会重新构造Bulk Request原因是前面已经将UpdateRequest翻译成了Index或Delete请求则后续所有Replica中只需要执行Index或Delete请求就可以了不需要再执行Update逻辑一是保证Replica中逻辑更简单性能更好二是保证同一个请求在Primary和Replica中的执行结果一样。 9.Flush Translog 这里会根据TransLog的策略选择不同的执行方式要么是立即Flush到磁盘要么是等到以后再Flush。Flush的频率越高可靠性越高对写入性能影响越大。 10.Send Requests To Replicas 这里会将刚才构造的新的Bulk Request并行发送给多个Replica然后等待Replica的返回这里需要等待所有Replica返回后可能有成功也有可能失败Primary Node才会返回用户。如果某个Replica失败了则Primary会给Master发送一个Remove Shard请求要求Master将该Replica Shard从可用节点中移除。 这里同时会将SequenceIDPrimaryTermGlobalCheckPoint等传递给Replica。 发送给Replica的请求中Action Name等于原始ActionName [R]这里的R表示Replica。通过这个[R]的不同可以找到处理Replica请求的Handler。 11.Receive Response From Replicas Replica中请求都处理完后会更新Primary Node的LocalCheckPoint。 Replica Node Replica 请求的入口是在ReplicaOperationTransportHandler的messageReceived. 1.Index or Delete 根据请求类型是Index还是Delete选择不同的执行逻辑。这里没有Update是因为在Primary Node中已经将Update转换成了Index或Delete请求了。 2.Parse Doc 3.Update Mapping 以上都和Primary Node中逻辑一致。 4.Get Sequence Id and Version Primary Node中会生成Sequence ID和Version然后放入ReplicaRequest中这里只需要从Request中获取到就行。 5.Add Doc To Lucene 由于已经在Primary Node中将部分Update请求转换成了Index或Delete请求这里只需要处理Index和Delete两种请求不再需要处理Update请求了。比Primary Node会更简单一些。 6.Write Translog 7.Flush Translog 以上都和Primary Node中逻辑一致。 数据分片 查询 Elasticsearch查询的详细过程是复杂的而它的核心部分就是倒排索引。这里将概述查询的过程包括分片的运用、主从节点的交互以及数据排序和结果汇总。 查询分发 当一个查询到达Elasticsearch时它首先被发送到一个协调节点coordinating node。这个节点负责解析查询确定需要从哪些分片shards检索数据并将查询请求转发到这些分片所在的节点。 主从节点交互 在Elasticsearch中每个索引被分为多个分片并且每个分片可以有一个或多个副本。副本分为主副本primary shard和从副本replica shard。查询可以在主分片或任何一个从分片上执行这有助于分散读取负载并提高查询性能。协调节点通常会根据分片的当前负载情况来决定发送查询请求给主分片或某个从分片。 本地查询处理 查询被发送到负责存储相关分片的节点后每个节点上的Elasticsearch进程会执行实际的查询操作。查询操作通常分为两个阶段 查询阶段Query Phase在这一阶段中Elasticsearch会检查查询条件并从倒排索引中查找匹配的文档ID。由于Elasticsearch使用的是倒排索引它可以非常高效地进行文本搜索。 取回阶段Fetch Phase一旦文档ID被查找到Elasticsearch就会进入取回阶段此时会根据需要从存储中检索文档的完整内容。如果查询包括了排序或聚合还可能需要在这个阶段对结果进行进一步处理。 结果排序与剪枝 如果查询请求指定了排序条件各个节点需要在本地对查询结果进行排序。每个节点只返回最顶端的结果例如如果请求指定了size: 10则每个节点只返回排名前10的结果给协调节点这样可以避免回传大量不必要的数据提高效率。 结果汇总 协调节点收到所有涉及的节点返回的结果后会进行最终的排序和汇总。然后协调节点会将最终的查询结果返回给客户端。 缓存 Elasticsearch还有一个查询缓存机制它会缓存经常被执行的过滤器查询的结果。这能够使得相同或相似的后续查询更快地返回结果。 查询复杂性可以根据查询中涉及的文档数量、查询类型如文本搜索、范围查询等、是否有聚合操作等因素有很大的不同。尽管Elasticsearch旨在使查询尽可能快速但一些复杂的查询还是会因为涉及大量的数据处理和传输而耗费较多时间。对于真正的性能要求通常需要结合监控、索引优化、查询优化等一系列措施来确保系统的查询响应效率。 分析器 什么是分析 分析(analysis)是在文档被发送并加入倒排索引之前,Elasticsearch在其主体上进行的操作。在文档被加入索引之前,Elasticsearch让每个被分析字段经过一系列的处理步骤。 字符过滤使用字符过滤器转变字符。文本切分为分词将文本切分为单个或多个分词。分词过滤使用分词过滤器转变每个分词。分词索引将这些分词存储到索引中。 使用到ElasticSearch的字符过滤器、分词器、分词过滤器和分词索引它们便组成了分析器analyzer。 字符过滤器 字符过滤器将特定的字符序列转变为其他的字符序列。可以用于将HTML从文本中剥离或者是将任意数量的字符转化为其他字符也许是将i love u 2”缩写的短消息纠正为i love you too”或者将“”替换为“and”等。 分词器 分词器是从文本片段生成的可能会产生任意数量甚至是0的分词(token)。例如在英文中一个通用的分词是标准分词器它根据空格、换行和破折号等其他字符将文本分割为分词。 例如将字符串“share your experience with NoSql and big data technologies分解为分词share、your、experience、with、NoSql、and、big、data 和 technologies。 分词过滤器 分词器文本块被转换为分词将会对每个分词运用分词过滤器tokenfilter。分词过滤器可以将一个分词作为输人然后根据需要进行修改添加或者是删除。 最为有用的和常用的分词过滤器是小写分词过滤器它将输人的分词变为小写确保在搜索词条nosql的时候可以发现关于“nosql的聚会。分词可以经过多于1个的分词过滤器每个过滤器对分词进行不同的操作将数据塑造为最佳的形式便于之后的索引。 分词索引 当经历了零个或者多个分词过滤器它们将被发送到Lucene进行文档的索引。这些分词组成了倒排索引。 配置分析器 配置分析器方式 当创建索引的时候为特定的索引进行设置。在Elasticsearch的配置文件中设置全局的分析器。 通常来说出于灵活性的考虑在创建索引或者是配置映射的时候指定分析器是更简单的。 创建索引配置分析器 分为两种一种是索引全局分析器另一种某个字段自定分析器 PUT /mall_order_test {settings: {number_of_shards: 1,number_of_replicas: 1,index:{# 分析器analysis: {analyzer: {# 设置分析器名称myCustomAnalyzer:{#定制化类型token:custom,# 字符过滤器char_filter:[myCustomCharFilter],# 分词器tokenizer:myCustomTokenizer,# 分词过滤器filter:[myCustomFilter1,myCustomFilter2],}}},# 定义字符过滤器char_filter:{myCustomCharFilter:{# 类型为映射把字符转成其他字符type:mapping,mappings:[phf,uyou]}}# 分词器tokenizer:{myCustomTokenizer:{# 分词器为 lettertype:letter}},# 分词过滤器filter:{myCustomFilter1:{# 小写分词过滤器type:lowercase},myCustomFilter2:{# kstem就行词干处理type:kstem}}}}, mappings:{properties:{orderTile:{type:text,#指定分词器es内置有多种analyzer:whitespace、standard、simple、stopanalyzer: myCustomAnalyzer }}} }如果想一个字段不被任何分析处理需要增加not_analyzed7.x之前 或者 typekeyword7.x之后 PUT /mall_order_test {mappings:{properties:{orderTile:{type:keyword}}} }用多字段类型来存储分析方式不同的文本 通常情况下可以同时搜索字段分析后的文本和原始、未经分析的文本是非常有用的。 PUT /mall_user {mappings: {properties: {name:{type: text, analyzer: standard,fields: {raw:{# keyword 即不分词type:keyword}}}}} }ElasticSearch配置分析器 index:analysis:analyer:myCustomAnalyzer:type: customchar_filter: [customCharFilter]tokenizer: customTokenizerfilter: [customFilter1,customFilter2]char_filter:customCharFilter:type: mappingmappings: [pff,uyou] tokenizer:customTokenizer:type: letterfilter:customFilter1:type: lowercase customFilter2:type: kstem内置分析器 一个分析器包括一个可选的字符过滤器、一个单个分词器、0个或多个分词过滤器。 standard-标准分析器 当没有指定分析器的时候标准分析器standard analyzer是文本的默认分析器。 它综合了对大多欧洲语言来说合理的默认模块包括标准分词器、标准分词过滤器、小写转换分词过滤器和停用词分词过滤器。 simple-简单分析器 简单分析器simpleanalyzer就是那么简单它只使用了小写转换分词器这意味着在非字母处进行分词并将分词自动转变为小写。 简单分析器对于亚洲语言来说效果不佳因为亚洲语言不是根据空白来分词所以请仅仅针对欧洲语言使用它。 whitespace-空白分析器 空白分析器whitespaceanalyzer什么事情都不做只是根据空白将文本切分为若干分词非常简单 stop-停用词分析器 停用词分析器analyzer和简单分析器的行为很相像只是在分词流中额外地过滤了停用词。 keyword-关键词分析器 关键词分析器keywordanalyzer将整个字段当作一个单独的分词。请记住最好是将index设置指定为notanalyzed7.x只有改为 typekeyword方式而不是在映射中使用关键词分析器。 pattern-模式分析器 模板分析器pattern analyzer允许你指定一个分词切分的模式。但是由于可能无论如何都要指定模式通常更有意义的做法是使用定制分析器组合现有的模式分词器和所需的分词过滤器。 Elasticsearch 的 Pattern Analyzer 是一个基于正则表达式的分词器(tokenizer)它允许用户使用正则表达式来定义如何将文本拆分为词(token)。下面举一个 Pattern Analyzer 的使用例子。 假设我们想要对一段日志数据进行分析这些日志数据的格式大致如下 127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] GET /apache_pb.gif HTTP/1.0 200 2326我们可能对从这些日志中提取出如 IP 地址、日期时间、请求方法、请求资源、响应状态码和响应大小等信息感兴趣。下面是如何在 Elasticsearch 中定义一个索引使用 Pattern Analyzer 来实现这一目标。 PUT /log_index {settings: {analysis: {analyzer: {log_analyzer: {type: pattern,pattern: \\s, // 使用空白字符做为分词分隔符lowercase: false // 不将词条转为小写}}}},mappings: {properties: {log: {type: text,analyzer: log_analyzer,fielddata: true // 由于后续可能需要对 log 字段进行聚合操作需要开启 fielddata}}} }在这个例子中我们定义了一个名为 log_analyzer 的分词器其类型为 pattern。我们指定了一个简单的正则表达式作为 pattern它用于匹配一个或多个空白字符(\\s)以此来分割日志的每一部分。我们还设置了 lowercase 为 false 来保持文本的原始大小写因为对于日志分析区分大小写可能是重要的。 创建了索引和相应的 Pattern Analyzer 之后就可以开始索引数据了 POST /log_index/_doc/1 {log: 127.0.0.1 - - [10/Oct/2000:13:55:36 -0700] \GET /apache_pb.gif HTTP/1.0\ 200 2326 }接着你可以通过执行搜索查询或聚合操作来分析日志数据 GET /log_index/_search {query: {match: {log: GET}} }这个搜索将会返回包含 GET 请求方法的所有日志条目。 请注意为简单起见这个例子只用了空格来分割日志条目并没有详细地去解析每个字段如 IP 地址等。在实际应用中你可能需要一个更复杂的正则表达式来准确提取和分析每个感兴趣的部分。此外对于复杂的日志分析可能需要定义更详细的字段映射来区分不同的日志组成部分如分别用不同字段存储 IP 地址、日期时间等。 snowball-雪球分析器 雪球分析器snowbal1analyzer除了使用标准的分词器和分词过滤器和标准分析器一样也使用了小写分词过滤器和停用词过滤器。它还使用了雪球词干器对文本进行词干提取。 内置分词器 standard-标准分词器 标准分词器standardtokenizer是一个基于语法的分词器对于大多数欧洲语言来说是不错的。它还处理了Unicode文本的切分不过分词默认的最大长度是255。它也移除了逗号和句号这样的标点符号。 POST _analyze {tokenizer: standard,text: The intersecting buckets e.g AC are labelled using a combination of the two filter names with a default separator of . }keyword-关键词分词器 关键词分词器keyword tokenizer是一种简单的分词器将整个文本作为单个的分词提供给分词过滤器。只想应用分词过滤器而不做任何分词操作时它可能非常有用。 letter-字母分词器 字母分词器letter tokenizer根据非字母的符号将文本切分成分词。例如对于句子share your experience with NoSql big data technologies”分词是share、your、experience、with、NoSql、big、data、technologies因为、空格和句号都不是字母 POST _analyze {tokenizer: letter,text: share your experience with NoSql big data technologies }lowercase-小写分词器 小写分词器lowercase tokenizer结合了常规的字母分词器和小写分词过滤器如你所想它将整个分词转化为小写的行为。通过一个单独的分词器来实现的主要原因是一次进行两项操作会获得更好的性能。 POST _analyze {tokenizer: lowercase,text: I am man. }分词结果是i、am、manI转换成i。 whitespace-空白分词器 空白分词器whitespace tokenizer通过空白来分隔不同的分词空白包括空格、制表符、换行等。请注意这种分词器不会删除任何标点符号。 POST _analyze {tokenizer: whitespace,text: share your experience with NoSql big data technologies }分词结果也包含“”。 pattern-模式分词器 模式分词器pattern tokenizer允许指定一个任意的模式将文本切分为分词。被指定的模式应该匹配间隔符号。 uax_url_emall - 电子邮件分词器 在处理英语单词的时候标准分词器是非常好的选择。但是当下存在不少以网站地址和电子邮件地址结束的文本。标准分析器可能在你未注意的地方对其进行了切分。 1.电子邮件分词 POST _analyze {tokenizer: uax_url_email,text: address is joygmail.com }分词结果address 、 is 、 joygmail.com 2.网址分词 POST _analyze {tokenizer: uax_url_email,text: domain is https://www.baidu.com }分词结果domain、is、https://www.baidu.com?siPhone path_hierarchy - 路径层次分词器 路径层次分词器path hierarchy tokenizer允许以特定的方式索引文件系统的路径这样在搜索时共享同样路径的文件将被作为结果返回。例如假设有一个文件名想要索引看上去是这样的/usr/local/var/log/elasticsearch.logo路径层次分词器将其切分为 POST _analyze {tokenizer: path_hierarchy,text: /usr/local/var/log/elasticsearch.logo }结果 {tokens : [{token : /usr,start_offset : 0,end_offset : 4,type : word,position : 0},{token : /usr/local,start_offset : 0,end_offset : 10,type : word,position : 0},{token : /usr/local/var,start_offset : 0,end_offset : 14,type : word,position : 0},{token : /usr/local/var/log,start_offset : 0,end_offset : 18,type : word,position : 0},{token : /usr/local/var/log/elasticsearch.logo,start_offset : 0,end_offset : 37,type : word,position : 0}] } 分词过滤器 standard-标准分词过滤器 不要认为标准分词过滤器standard token filter进行了什么复杂的计算实际上它什么事情也没做在更老版本的Lucene中它用于去除单词结尾的s”字符还有不必要的句点字符但是现在这些都被其他的分词过滤器和分词器处理掉了。 注意标准分词过滤器在 7.x之后被移除。 POST _analyze {text: I am man.,filter: [{type: standard}] }lowercase - 小写分词过滤器 小写分词过滤器lowercase token filter只是做了这件事将任何经过的分词转换为小写。 POST _analyze {text: I am man.,filter: [{type: lowercase}] }输出 {tokens : [{token : i am man.,start_offset : 0,end_offset : 9,type : word,position : 0}] }创建索引时指定分词过滤器 PUT /mall_user {settings: {index: {analysis:{analyzer:{customLowercaseAnalyzer:{type:custom,tokenizer:standard,filter:[lowercase,stop]}}}}},mappings: {properties: {name: {type: text,analyzer: customLowercaseAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }查询name的词条 # 写入数据 POST /mall_user/_doc/1 {name:i am Jay,age:20,birth:2002-01-01 }# 分析词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }由于使用了lowercase分词过滤器Jay会被转换成jay通过Jay或者jay都可以进行搜索。 length - 长度分词过滤器 长度分词过滤器length token filter将长度超出最短和最长限制范围的单词过滤掉。举个例子如果将min设置为2并将max设置为5任何小于2个字符和任何大于5个字符的分词将会被移除。 POST _analyze {text: I am man.,tokenizer: standard,filter: [{type: length,min: 2,max: 5}] }max参数表示最大分词长度默认为Integer.MAX_VALUE就是2147483647。 min则表示最小长度默认为0 输出结果 {tokens : [{token : am,start_offset : 2,end_offset : 4,type : ALPHANUM,position : 1},{token : man,start_offset : 5,end_offset : 8,type : ALPHANUM,position : 2}] }I和符号.长度不在2-5之间都被过滤。 创建索引时指定分词过滤器 PUT /mall_user {settings: {index: {analysis: {filter:{customLengthFilter:{type:length,min:2,max:5}},analyzer: {customLengthAnaylyzer: {type: custom,tokenizer: standard,filter: [customLengthFilter]}}}}},mappings: {properties: {name: {type: text,analyzer: customLengthAnaylyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }写入数据 POST /mall_user/_doc/1 {name:i am Jay,age:20,birth:2002-01-01 }查询name的词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }输出结果 {_index : mall_user,_type : _doc,_id : 1,_version : 1,found : true,took : 0,term_vectors : {name : {field_statistics : {sum_doc_freq : 2,doc_count : 1,sum_ttf : 2},terms : {Jay : {term_freq : 1,tokens : [{position : 2,start_offset : 5,end_offset : 8}]},am : {term_freq : 1,tokens : [{position : 1,start_offset : 2,end_offset : 4}]}}}} }从结果看i 长度不在2-5之间已被过滤。 查询 # 查询 name 包含 i 的信息输出为空 POST /mall_user/_search {query: {match: {name: i}} }# 查询 name 包含 Jay 的信息找到对应的记录 POST /mall_user/_search {query: {match: {name: Jay}} }stop - 停用词分词过滤器 停用词分词过滤器stop token filter将停用词从分词流中移除。对于英文而言这意味着停用词列表中的所有分词都将每会被完全移除。可以添加指定一个待移除单词的列表。 POST _analyze {text: I am man.,tokenizer: standard,filter: [{type: stop,stopwords:[am]}] }stopwords:自定义的待移除单词的列表。 输出 {tokens : [{token : I,start_offset : 0,end_offset : 1,type : ALPHANUM,position : 0},{token : man,start_offset : 5,end_offset : 8,type : ALPHANUM,position : 2}] }从结果来看已经移除am单词。 创建索引时指定分词过滤器 PUT /mall_user {settings: {index: {analysis: {filter:{customStopFilter:{type:stop,stopwords:[am]}},analyzer:{customStopAnalyzer:{type:custom,tokenizer:standard,filter:[customStopFilter]}}}}},mappings: {properties: {name: {type: text,analyzer: customStopAnalyzer, fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }除stopwords参数还也可以使用stopwords_path参数指定停用词文件。 写入数据 POST /mall_user/_doc/1 {name:am Jay,age:20,birth:2002-01-01 }查询分词信息 POST /mall_user/_doc/1/_termvectors {fields: [name] }只有Jay分词。 使用am词搜索 POST /mall_user/_search {query: {match: {name: am}} }搜索结果为空。 reverse - 反转分词过滤器 反转分词过滤器reverse token filter允许处理一个分词流并反转每个分词。 使用反转分词过滤器测试文本 POST _analyze {text: I am man.,tokenizer: standard,filter: [reverse] }创建索引时指定分析器 PUT /mall_user {settings: {index: {analysis:{analyzer:{customReverseAnalyzer:{type:custom,tokenizer:standard,filter:[reverse]}}}}},mappings: {properties: {name: {type: text,analyzer: customReverseAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }写入数据并且查看name词条和搜索 #写入数据 POST /mall_user/_doc/1 {name:i am Jay,age:20,birth:2002-01-01 }# 查询name的词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }# 搜索 POST /mall_user/_search {query: {match: {name: Jay}} }unique - 唯一分词过滤器 唯一分词过滤器unique token filter只保留唯一的分词它保留第一个匹配分词的元数据而将其后出现的重复删除 POST _analyze {text: foo bar foo bar,tokenizer: standard,filter: [unique] }创建索引时指定唯一分词过滤器 PUT /mall_user {settings: {index: {analysis:{analyzer:{customUniqueAnalyzer:{type:custom,tokenizer:standard,filter:[unique]}}}}},mappings: {properties: {name: {type: text,analyzer: customUniqueAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }查看name词条 # 写入数据 POST /mall_user/_doc/1 {name:foo bar foo bar,age:20,birth:2002-01-01 }# 查看name词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }synonym - 同义词分词过滤器 同义词分词过滤器synonym token filter在分词流中的同样位移处使用关键词的同义词取代原分词。 例如文本“i have a automobile”automobile 的同义词为car。 POST _analyze {text: i have a automobile,tokenizer: standard,filter: [{type:synonym,synonyms:[automobilecar]} ] }输出结果没有automobile已替换成car。 创建索引时使用同义词 PUT /mall_user {settings: {index: {analysis:{filter:{customSynonymFilter:{type:synonym,synonyms:[automobilecar]}},analyzer:{customSynonymAnalyzer:{type:custom,tokenizer:standard,filter:[customSynonymFilter]}}}}},mappings: {properties: {name: {type: text,analyzer: customSynonymAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }写入数据和测试name的词条 POST /mall_user/_doc/1 {name:i have a automobile,age:20,birth:2002-01-01 }# 查看词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }# 使用car 或者 automobile搜索 都可以搜索到结果 POST /mall_user/_search {query: {match: {name: automobile}} } POST /mall_user/_search {query: {match: {name: car}} }ngram - N元语法分词过滤器 什么是N元语法 N元语法ngram是Elasticsearch中更为独特的分词方式。N元语法是将一个单词切分为多个子单词。 N元语法具体表现为1元语法、2元语法等。 1元语法1-ngram分词“automobile”结果时a、u、t、o、m、o、b、i、l、e。 2元语法2-ngram分词“automobile”结果时au、ut、to、om、mo、ob、bi、il、le。 由此可以看出N元语法是按字符的顺序往后截取N个字符。 使用N元语法分析文本 # 1元语法 POST _analyze {text: automobile,tokenizer: standard,filter: [{type:ngram,min_gram:1,max_gram:1} ] }#2元语法 POST _analyze {text: automobile,tokenizer: standard,filter: [{type:ngram,min_gram:2,max_gram:2} ] }min_gram:最小分隔的大小 max_gram:最大分隔的大小 max_gram 和 min_gram 的差值需要在index.max_ngram_diff之间。 如果min_gram1、max_gram2automobile分割成a、u、t、o、m、o、b、i、l、e、au、ut、to、om、mo、ob、bi、il、le。 创建索引时使用N元语法 PUT /mall_user {settings: {index: {analysis:{filter:{customNgramFilter:{type:ngram,min_gram:1,max_gram:1}},analyzer:{customNgramAnalyzer:{type:custom,tokenizer:standard,filter:[customNgramFilter]}}}}},mappings: {properties: {name: {type: text,analyzer: customNgramAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }写入数据并且查看name词条、通过name查询 # 写入数据 POST /mall_user/_doc/1 {name:automobile,age:20,birth:2002-01-01 }# 查看词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }# 查询name类似a的文档能查询到 POST /mall_user/_search {query: {match: {name: a}} }edge_ngram - 侧边N元语法 侧边N元语法是普通N元语法切分的一种变体仅仅从左边的边缘开始构建N元语法。 例如“automobile”从左边“a”的边缘开始截取N个词。 POST _analyze {text: automobile,tokenizer: standard,filter: [{type:edge_ngram,min_gram:2,max_gram:4} ] }输出au、aut、auto此时已经注意到超过max_ngram部分不会分割意味着不能搜索。 创建索引时使用侧边N元语法 PUT /mall_user {settings: {index: {analysis:{filter:{customEdgeNgramFilter:{type:edge_ngram,min_gram:2,max_gram:4}},analyzer:{customEdgeNgramAnalyzer:{type:custom,tokenizer:standard,filter:[customEdgeNgramFilter]}}}}},mappings: {properties: {name: {type: text,analyzer: customEdgeNgramAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }写入数据、查看name词条和根据name查询数据 #写入数据 POST /mall_user/_doc/1 {name:automobile,age:20,birth:2002-01-01 }#查询name词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }# 根据name查询 # au、aut、auto 可以查询到数据 # mobile 字符是不能搜索到数据的超过max_gram没有分割 POST /mall_user/_search {query: {match: {name: au}} }shingle - 滑动窗口分词过滤器 滑动窗口分词过滤器shingles和N元语法以及侧边N元语法沿用了同样的方式。滑动窗口分词过滤器基本上是分词级别的N元语法而不是字符级别的N元语法。 例如“i has a automobile”分割成i、i has、has、has a、a、a automobile POST _analyze {text: i has a automobile,tokenizer: standard,filter: [{type:shingle,min_shingle_size:2,max_shingle_size:2} ] }创建索引时使用滑动窗口分词过滤器 PUT /mall_user {settings: {index: {analysis:{filter:{customShingleFilter:{type:shingle,min_shingle_size:2,max_shingle_size:2}},analyzer:{customShingleAnalyzer:{type:custom,tokenizer:standard,filter:[customShingleFilter]}}}}},mappings: {properties: {name: {type: text,analyzer: customShingleAnalyzer,fields: {raw: {type: keyword}}},age: {type: integer},birth: {type: date,format: yyyy-MM-dd}}} }写入数据、查询name的词条、使用name查询 # 写入数据 POST /mall_user/_doc/1 {name:i has a automobile,age:20,birth:2002-01-01 }# 查看name的词条 POST /mall_user/_doc/1/_termvectors {fields: [name] }# 根据name搜索 POST /mall_user/_search {query: {match: {name: has}} } 提取词干-词干分词过滤器 提取词干是将单词缩减到基本或词根的形式。在搜索的时候这种处理是非常方便的因为这意味着用户可以匹配单词的复数以及有同样词根的单词因此名字称为“提取词干。 提取词干的算法有snowball过滤器、porter_stem过滤器、kstem过滤器。他们表现基本一致不过在提取词干有多激进的方面有一些细微的差别。这里的“激进是指相对于不激进的词干提取器更为激进的词干提取器会砍掉单词更多的部分。 snowball过滤器 POST _analyze {text: administrations administrators Administrate,tokenizer: standard,filter: [{type:snowball} ] }porter_stem 过滤器 POST _analyze {text: administrations administrators Administrate,tokenizer: standard,filter: [{type:porter_stem} ] }kstem过滤器 POST _analyze {text: administrations administrators Administrate,tokenizer: standard,filter: [{type:kstem} ] }输出结果对比 算法administrationsadministratorsAdministratesnowballadministradministrAdministrporter_stemadministradministrAdministrkstemadministrationadministratorAdministrate 除此之外还可以使用词典提取词干 有的时候算法词干提取会以一种奇怪的方式来提取单词的词干因为它们并不理解基层的语言。正因为此存在更为精确的方式来提取词干那就是使用单词字典。在Elasticsearch中可以使用hunspell分词过滤器结合一个字典来处理词干。 基于此词干提取的质量就和所用字典的质量是直接相关的。词干提取器只能处理字典里存在的单词。 当创建一个hunspell分析器的时候字典文件应该是在名为hunspell的目录里并且hunspell目录和elasticsearch.yml处于同一个目录中。在hunspell目录中每种语言的字典是一个以其关联地区命名的目录。 使用分析API分析文本 当跟踪信息是如何在Elasticsearch索引中存储的时候使用分析API来测试分析的过程是十分有用的。API允许你向Elasticsearch发送任何文本指定所使用的分析器、分词器或者分词过滤器然后获取分析后的分词。使用标准分析分析了文本share your experience with NoSql big data technologies 1.使用内置的分析器分析 POST _analyze {text: [share your experience with NoSql big data technologies],analyzer: standard }输出结果 {tokens : [{token : share,start_offset : 0,end_offset : 5,type : ALPHANUM,position : 0},{token : your,start_offset : 6,end_offset : 10,type : ALPHANUM,position : 1},{token : experience,start_offset : 11,end_offset : 21,type : ALPHANUM,position : 2},{token : with,start_offset : 22,end_offset : 26,type : ALPHANUM,position : 3},{token : nosql,start_offset : 27,end_offset : 32,type : ALPHANUM,position : 4},{token : big,start_offset : 35,end_offset : 38,type : ALPHANUM,position : 5},{token : data,start_offset : 39,end_offset : 43,type : ALPHANUM,position : 6},{token : technologies,start_offset : 44,end_offset : 56,type : ALPHANUM,position : 7}] }分析API中最为重要的输出是token键。输出是一组这样映射的列表代表了处理后的分词实际上这些分词将会被写人到索引中。 2.通过组合即时使用分析器分析 POST _analyze {text: [share your experience with NoSql big data technologies],char_filter: {type: mapping,mappings: [and]},tokenizer: {type: whitespace},filter: [# 转小写{type: lowercase},# 翻转字符{type: reverse}] }输出 {tokens : [{token : share,start_offset : 0,end_offset : 5,type : word,position : 0},{token : your,start_offset : 6,end_offset : 10,type : word,position : 1},{token : experience,start_offset : 11,end_offset : 21,type : word,position : 2},{token : with,start_offset : 22,end_offset : 26,type : word,position : 3},{token : nosql,start_offset : 27,end_offset : 32,type : word,position : 4},{token : and,start_offset : 33,end_offset : 34,type : word,position : 5},{token : big,start_offset : 35,end_offset : 38,type : word,position : 6},{token : data,start_offset : 39,end_offset : 43,type : word,position : 7},{token : technologies,start_offset : 44,end_offset : 56,type : word,position : 8}] }3.使用现有索引字段分析器分析 POST /mall_order_test/_analyze {text: share your experience with NoSql big data technologies,field:orderTitle }使用 mall_order_test 索引中orderTitle字段使用的分词器分析text文本。 查询索引文档的分词信息 通过_termvectors查询已经索引的文档orderTitle字段的分词词条操作消耗比较大 POST /mall_order_test/_doc/sZNUsIwBSLqPVZ3tlB7z/_termvectors?prettytrue {fields:[orderTitle] }输出 {_index : mall_order_test,_type : _doc,_id : sZNUsIwBSLqPVZ3tlB7z,_version : 8,found : true,took : 0,term_vectors : {# orderTitle 词条信息orderTitle : {field_statistics : {# 该字段中所有词条的文档频率之和sum_doc_freq : 9,# 包含该字段的文档数量doc_count : 1,# 字段中所有词条频率之和sum_ttf : 9},terms : {# 16000 词条的结果数据16000 : {# 词条在该字段中出现的次数term_freq : 1,tokens : [{position : 7,start_offset : 20,end_offset : 25}]},iphone15 : {term_freq : 1,tokens : [{position : 0,start_offset : 0,end_offset : 8}]},max : {term_freq : 1,tokens : [{position : 2,start_offset : 13,end_offset : 16}]},pro : {term_freq : 1,tokens : [{position : 1,start_offset : 9,end_offset : 12}]},元 : {term_freq : 1,tokens : [{position : 8,start_offset : 25,end_offset : 26}]},单 : {term_freq : 1,tokens : [{position : 4,start_offset : 17,end_offset : 18}]},订 : {term_freq : 1,tokens : [{position : 3,start_offset : 16,end_offset : 17}]},金 : {term_freq : 1,tokens : [{position : 5,start_offset : 18,end_offset : 19}]},额 : {term_freq : 1,tokens : [{position : 6,start_offset : 19,end_offset : 20}]}}}} } 快照和恢复 Elasticsearch 的快照和恢复功能允许用户备份集群中的数据并在需要时恢复。快照可以是手动触发的也可以通过自动化机制进行定期备份。以下是有关如何配置和使用 Elasticsearch 自动快照和恢复机制的步骤 快照仓库注册 在配置自动快照之前首先需要定义一个快照仓库。Elasticsearch 支持多种类型的仓库包括文件系统FS、Amazon S3、Google Cloud Storage、Azure Blob Storage 等。仓库需要在集群中预先定义好如下所示 PUT /_snapshot/my_backup_repository {type: fs,settings: {location: /mount/backups/my_backup,compress: true} }在上述例子中注册了一个文件系统类型的仓库名为 my_backup_repository并指定了备份文件的位置和压缩选项。 创建自动快照策略 通过 Elasticsearch 的 SLMSnapshot Lifecycle Management功能你可以定期自动创建快照。你需要创建一个快照生命周期策略如下所示 PUT /_slm/policy/daily_snapshots {schedule: 0 30 1 * * ?, name: my-snap-{now/d},repository: my_backup_repository,config: {indices: [*],ignore_unavailable: true,include_global_state: false},retention: {expire_after: 30d,min_count: 5,max_count: 50} }这个例子中定义了一个名为 daily_snapshots 的策略它会在每天凌晨 1:30服务器时间自动创建一个快照。快照会被保存在前面注册的 my_backup_repository 仓库中。策略还定义了保留策略以控制保存快照的时间长短。 恢复快照 若要恢复先前创建的快照可以使用以下命令 POST /_snapshot/my_backup_repository/my-snap-2023.04.06_01:30/_restore {indices: index_1,index_2,ignore_unavailable: true,include_global_state: true }上面的命令会从 my_backup_repository 仓库中恢复名为 my-snap-2023.04.06_01:30 的快照包括 index_1 和 index_2 这两个索引。 监控和管理快照 你可以通过 Elasticsearch 的各种 API 来监控和管理快照和快照策略。例如检查快照状态 GET /_snapshot/my_backup_repository/my-snap-2023.04.06_01:30或者获取当前生命周期策略的状态 GET /_slm/policy上面介绍了 Elasticsearch 自动快照和恢复机制的基本步骤。请注意一切配置和操作都要考虑到你的实际环境和需求。Elasticsearch 的版本和配置可能会影响具体步骤和可用功能。
http://www.dnsts.com.cn/news/43813.html

相关文章:

  • 深圳网站建设如何制作域名iis网站添加
  • 石大远程网页设计及网站建设答案二级域名的网站备案
  • 重庆网站设计生产厂家建立网站需要钱吗
  • 网站建设需要多少深圳易捷网站建设
  • 网站建设中端口号的作用是什么意思用什么语言能写网站吗
  • 32套网站后台管理系统模板北京服务器租用
  • 广州做网站最好的公司成都网站设计排名的公司价格
  • 下载官方网站app下载农商1号的网站建设费
  • 网络公共关系seo技术员
  • 长沙网站排名推广百度网网站建设的目标
  • 中国设计师联盟网站asp购物网站源码
  • 东莞网络建站公司网站设计网络推广
  • 优化网站关键词哈尔滨建设工程招标网
  • 贵阳有哪些可以制作网站的公司吗企业信用信息公示官网
  • 长沙做网站的公司对比如何规划企业网络推广方案
  • 百度网站推广咨询网站设计流程是
  • 苏州企业如何建网站网站开发实验总结
  • 做网站大图片中国郴州
  • 大学网站策划方案各国网站的域名
  • 公司网站建设开发wordpress下载主题模板
  • 呼和浩特网站制作公司唐山百度网站建设
  • 汕头龙湖网站建设网站内容管理系统怎么用
  • wordpress网站域名地址如何查看网站图片尺寸
  • 泉州做网站工资品牌设计得公司
  • 设计类专业网站东莞高端网站建设公司
  • 芮城网站建设苏州建设工程质量监督网站
  • 网站整套模板优化网站的步骤
  • 网站开发得多长时间网页设计班学费
  • 教育培训网站抄袭网站做违法的事情投诉
  • 响应式网站文章搜云seo