• 笔记-Elasticsearch搜索引擎构建入门与实战


    协调节点根据数据获取分片ID的计算公式如下:shard=hash(routing)%number_of_primary_shards
    第三方数据同步模块(如Canal)负责将数据库中的数据按照业务需求同步到ES中
    在ES中进行纠错匹配时使用fuzzy-match搜索
    match搜索对某个字段进行模糊匹配

    别名表示别名和索引之间的包含关系 一个别名可以对应多个索引 或者正则匹配的一系列索引
    默认情况下,当一个别名只指向一个索引时,写入数据的请求可以指向这个别名,如果这个别名指向多个索引(就像上面的例子),则写入数据的请求是不可以指向这个别名的,别名设置时,将目标索引的is_write_index属性值设置为true来指定该索引可用于执行数据写入操作

    keyword类型是不进行切分的字符串类型。这里的“不进行切分”指的是:在索引时,对keyword类型的数据不进行切分,直接构建倒排索引;在搜索时,对该类型的查询字符串不进行切分后的部分匹配。keyword类型数据一般用于对文档的过滤、排序和聚合
    在现实场景中,keyword经常用于描述姓名、产品类型、用户ID、URL和状态码等。keyword类型数据一般用于比较字符串是否相等,不对数据进行部分匹配,因此一般查询这种类型的数据时使用term查询。
    对keyword类型使用match搜索进行匹配是不会命中文档的。

    text类型是可进行切分的字符串类型。这里的“可切分”指的是:在索引时,可按照相应的切词算法对文本内容进行切分,然后构建倒排索引;在搜索时,对该类型的查询字符串按照用户的切词算法进行切分,然后对切分后的部分匹配打分。

    term搜索用于搜索值和文档对应的字段是否完全相等,而对于text类型的数据,在建立索引时ES已经进行了切分并建立了倒排索引,因此使用term没有搜索到数据。一般情况下,搜索text类型的数据时应使用match搜索。
    ES支持的数值类型有long、integer、short、byte、double、float、half_float、scaled_float和unsigned_long等,数值类型的数据也可用于对文档进行过滤、排序和聚合
    布尔类型使用boolean定义,可以用term过滤

    在ES中,日期类型的名称为date。ES中存储的日期是标准的UTC格式 可以用范围查询或者term查询
    1.数组类型 数组元素类型是keyword,该类型可以适用于term搜索
    2.对象类型 搜索需要看对象类型里面的字段类型

    geo_point类型

    批量写入文档 POST /_bulk insert /BulkRequest InsertRequest
    更新单条文档 POST / i n d e x n a m e / u p d a t e / {index_name}/_update/ indexname/update/{_id} UpdateRequest.update
    更新或插入单条文档 POST / i n d e x n a m e / u p d a t e / {index_name}/_update/ indexname/update/{_id} upsert UpdateRequest -upsert
    批量更新文档 POST /_bulk update /BulkRequest UpdateRequest
    条件更新 POST / i n d e x n a m e / u p d a t e b y q u e r y u p d a t e B y Q u e r y R e q u e s t q u e r y ( ) s r i p t 删除单条文档 D E L E T E / {index_name}/_update_by_query updateByQueryRequest query() sript 删除单条文档 DELETE / indexname/updatebyqueryupdateByQueryRequestquery()sript删除单条文档DELETE/{index_name}/_doc/ i d D e l e t e R e q u e s t 批量删除文档 P O S T / b u l k d e l e t e / B u l k R e q u e s t D e l e t e R e q u e s t 根据条件删除文档 P O S T / {_id} DeleteRequest 批量删除文档 POST /_bulk delete /BulkRequest DeleteRequest 根据条件删除文档 POST / idDeleteRequest批量删除文档POST/bulkdelete/BulkRequestDeleteRequest根据条件删除文档POST/{index_name}/_delete_by_query DeleteByQueryRequest TermQueryBuilder
    searchSourceBuilder.fetchSource()方法可以设定搜索返回的字段
    结果计数 GET /hotel/_count SearchSourceBuilder CountRequest TermQueryBuilder
    分页是必不可少的功能。在默认情况下,ES返回前10个搜索匹配的文档 默认情况下,用户最多可以取得10 000个文档
    返回多于10 000条的数据,可以适当修改max_result_window的值

    作为一个分布式搜索引擎,一个ES索引的数据分布在多个分片中,而这些分片又分配在不同的节点上。一个带有分页的搜索请求往往会跨越多个分片,每个分片必须在内存中构建一个长度为from+size的、按照得分排序的有序队列,用以存储命中的文档。然后这些分片对应的队列数据都会传递给协调节点,协调节点将各个队列的数据进行汇总,需要提供一个长度为number_of_shards*(from+size)的队列用以进行全局排序,然后再按照用户的请求从from位置开始查找,找到size个文档后进行返回。

    作为搜索引擎,ES更适合的场景是对数据进行搜索,而不是进行大规模的数据遍历。
    SearchSourceBuilder的from()和size()方法来设定from和size参数
    ES提供了profile功能,该功能详细地列出了搜索时每一个步骤的耗时,可以帮助用户对DSL的性能进行剖析。开启profile功能只需要在一个正常的搜索请求的DSL中添加"profile":"true"即可

    ES提供了explain功能来帮助使用者查看搜索时的匹配详情 GET / i n d e x n a m e / e x p l a i n / {index_name}/_explain/ indexname/explain/{doc_id} { “query”: { //搜索的具体逻辑 … } }

    ES提供了很多搜索匹配功能:既有进行完全匹配的term搜索,也有按照范围匹配的range搜索;既有进行分词匹配的match搜索,也有按照前缀匹配的suggest搜索
    query match_all查询所有文档 SearchRequest SearchSourceBuilder MatchAllQueryBuilder

    term查询是结构化精准查询的主要查询方式,用于查询待查字段和查询值是否完全匹配 QueryBuilders.termQuery()方法新建一个term查询
    terms查询是term查询的扩展形式,用于查询一个或多个值与待查字段是否完全匹配 QueryBuilders.termsQuery() 可变长度参数
    range查询用于范围查询,一般是对数值型和日期型数据的查询 QueryBuilders.rangeQuery() gt:大于;·lt:小于;·gte:大于或等于;·lte:小于或等于。

    exists 查询 GET /hotel_1/_search { “query”: { “exists”: { //查询tag字段不为空的文档 “field”: “tag” } } } 字段不为空的条件有:·值存在且不是null;·值不是空数组;·值是数组,但不是[null]。
    SearchSourceBuilder.existsQuery
    布尔查询是常用的复合查询 支持的子查询有四种 must 必须 should 可以 must_not 必须不 filter(不计分)
    should查询时,表示当前查询为“或”查询 should查询包含一个数组,可以把其他的term级别的查询及布尔查询放入其中。 QueryBuilders.boolQuery().should()
    查询中包含must not查询时,表示当前查询为“非”查询 must not查询包含一个数组,可以把其他term级别的查询及布尔查询放入其中
    QueryBuilders.boolQuery().mustNot()

    filter查询即过滤查询,该查询是布尔查询里非常独特的一种查询.
    其他布尔查询关注的是查询条件和文档的匹配程度,并按照匹配程度进行打分;而filter查询关注的是查询条件和文档是否匹配,不进行相关的打分计算,但是会对部分匹配结果进行缓存
    QueryBuilders.boolQuery().filter()
    当一个请求中有多个filter查询条件时,ES会构建多个bitset数组 ES对于bitset是可重用的,这种重用的机制叫作filter cache(过滤器缓存) 最近256个查询
    Constant Score查询
    如果不想让检索词频率TF(Term Frequency)对搜索结果排序有影响,只想过滤某个文本字段是否包含某个词,可以使用Constant Score将查询语句包装起来
    GET /hotel/_search query constant_score ConstantScoreQueryBuilder
    干预“相关度”,此时就可以使用Function Score查询

    QueryBuilders.functionScoreQuery()
    全文搜索 全文指的是文本类型数据(text类型)
    match查询match查询是全文搜索的主要代表。对于最基本的math搜索来说,只要分词中的一个或者多个在文档中存在即可。
    match搜索可以设置operator参数,该参数决定文档按照分词后的词集合进行“与”还是“或”匹配。在默认情况下,该参数的值为“与”关系,即operator的值为or,这也解释了搜索结果中包含部分匹配的文档。如果希望各个词之间的匹配结果是“与”关系,则可以设置operator参数的值为and
    minimum_should_match参数,该参数叫作最小匹配参数,其值为一个数值,意义为可以匹配上的词的个数。在一般情况下将其设置为一个百分数
    QueryBuilders.matchQuery()方法构建match请求
    在多个字段中查询关键词使用multi_match QueryBuilders.multiMatchQuery
    match_phrase用于匹配短语,与match查询不同的是,match_phrase用于搜索确切的短语或邻近的词语。
    match_phrase查询的slop参数,它用来调节匹配词之间的距离阈值。QueryBuilders.matchPhraseQuery()

    对应于geo_point字段类型的查询方式有3种,分别为geo_distance查询、geo_bounding_box查询和geo_polygon
    QueryBuilders.geoDistanceQuery geo_shape查询提供的是矩形内的搜索
    geo_polygon比geo_shape提供的地理范围功能更加灵活,它支持多边形内的文档搜索
    QueryBuilders.geoPolygonQuery GeoPoint

    搜索建议 自动补全 (前缀查询)ES中的Completion Suggester是比较合适的,为了使用Completion Suggester,其对应的字段类型需要定义为completion类型
    搜索建议的结果不是封装在hits中,而是单独封装在suggest中。在suggest.hotel_zh_sug.options中可以看到每一个候选集的文档信息
    使用SuggestBuilder方法构建搜索建议请求。使用suggestBuilder.addSuggestion()方法添加具体的搜索建议 CompletionSuggestionBuilder
    ES提供的Completion Suggester功能使用的索引结构不是倒排索引,而是在内存中构建FST(Finite StateTransducers)

    使用sort子句一般是按照字段信息进行排序,不受相关性影响 也可以使用sort对搜索结果按照多个字段进行排序 写在前面的是首要排序
    默认情况下ES查询时使用sort对结果排序是不计算分数的
    SortBuilders.geo DistanceSort()

    ES在文本索引的建立和搜索过程中依赖两大组件,即Lucene和分析器。其中,Lucene负责进行倒排索引的物理构建,分析器负责在建立倒排索引前和搜索前对文本进行分词和语法处理,处理的过程包括字符过滤、分词和分词过滤,最终的处理结果是文档内容被表示为一系列关键词信息的集合

    match查询过程一般分为如下几步:(1)ES将查询的字符串传入对应的分析器中,分析器的主要作用是对查询文本进行分词,并把分词后的每个词语变换为对应的底层lucene term查询。(2)ES用term查询在倒排索引中查找每个term,然后获取一组包含该term的文档集合。(3)ES根据文本相关度对每个文档进行打分计算,打分完毕后,ES把文档按照相关性进行倒序排序。(4)ES根据得分高低返回匹配的文档。

    分析器一般用在下面两个场景中:·创建或更新文档时(合称索引时),对相应的文本字段进行分词处理;·查询文本字段时,对查询语句进行分词。ES中的分析器有很多种,但是所有分析器的结构都遵循三段式原则,即字符过滤器、分词器和词语过滤器。其中,字符过滤器可以有0个或多个,分词器必须只有一个,词语过滤器可以有0个或多个。
    ES 内置 映射关系字符过滤器 HTML 正则表达式过滤器
    分词器内置: 标准 standard、字母 小写Lower Case 空格 、停用词 同义词
    默认情况下,一个索引的字段类型为text时,该字段在索引建立时和查询时的分析器是standard。standard分析器是由standard分词器、Lower Case分词过滤器和Stop Token分词过滤器构成的
    ES还提供了simple分析器、language分析器、whitespace分析器及pattern分析器等
    搜索分析器和索引时的分析器默认是一致的,但是在大多数情况下是没有必要指定的
    IK分析器是一个开源的、基于Java语言开发的轻量级的中文分词工具包,它提供了多种语言的调用库
    IK分析器提供了两个子分析器,即ik_smart和ik_max_word
    ik_max_word和ik_smart分析器的主要区别在于切分词语的粒度上,ik_smart的切分粒度比较粗,而ik_max_word将文本进行了最细粒度的拆分,甚至穷尽了各种可能的组合
    IK分析器添加词典 下的config子目录中创建文件my.dict,在其中添加“嘉怡”即可。如果有更多的词语需要添加,则每个词语单独一行
    添加完成后修改IK分析器的配置文件,路径为config/IKAnalyzer.cfg.xml,将新建的字典文件加入ext_dict选项中,
    配置完成后重启ES
    HanLP分析器提供了众多的子分析器,如hanlp、hanlp_standard、hanlp_crf和hanlp_n_short等
    hanlp_standard 和IK的smart类似
    HanLP分析器会在后台每隔一段时间(大约1min)对分词词典进行自动热更新。每轮更新完成之后,新添加的词语即可被用户使用。
    用户还可以通过ES中的分析器来使用同义词,使用方式分为两种,一种是在建立索引时指定同义词并构建同义词的倒排索引,另一种是在搜索时指定字段的search_analyzer查询分析器使用同义词。
    建立索引时使用同义词 synonyms,它是一种支持用户自定义同义词的分词过滤器
    查询时使用同义词 synonym_graph 有更新同义词的需求,则只能使用查询时使用同义词的这种方式。首先需要先关闭当前索引,更改索引的settings信息,新添加一组近义词
    ES支持用户将同义词放在文件中,文件的位置必须是在 E S H O M E / c o n f i g 目录及其子目录下如果同义词比较多,在 s e t t i n g s 中进行配置时将非常烦琐。 E S 支持用户将同义词放在文件中,文件的位置必须是在 {ES_HOME}/config目录及其子目录下 如果同义词比较多,在settings中进行配置时将非常烦琐。ES支持用户将同义词放在文件中,文件的位置必须是在 ESHOME/config目录及其子目录下如果同义词比较多,在settings中进行配置时将非常烦琐。ES支持用户将同义词放在文件中,文件的位置必须是在{ES_HOME}/config目录及其子目录下,注意该文件必须存在于ES集群中的每一个节点上。在${ES_HOME}/config目录下建立一个子目录mydict
    创建酒店索引时,在settings中指定同义词文件及其路径 更新同义词时 POST /hotel/_reload_search_analyzers 才能使用新词
    停用词也叫停止词,是指文本在被分词之后的词语中包含的无搜索意义的词 在构建搜索引擎索引时,常常忽略这样的词,这样可以大大提升搜索效率。经常使用的中文和英文停用词可以在网站www.ranks.nl上提取,中文停用词地址为https://www.ranks.nl/stopwords/chinese-stopwords,英文停用词地址为https://www.ranks.nl/stopwords
    可以通过创建自定义分析器的方式使用停用词
    默认情况下,IK分析器的分词器只有英文停用词,没有中文停用词,配置完成后重启ES
    默认情况下,HanLP分析器的停用词是不启用的 重启ES
    拼音分析器提供的分析器为pinyin,另外还提供了与其同名的分词器和分词过滤器
    使用Java客户端进行高亮显示搜索时,需要创建一个HighlightBuilder类的实例,然后通过preTags()和postTags()方法分别设置高亮显示的前缀和后缀,并通过方法field()设置高亮显示的字段。遍历结果时,通过SearchHit.getHighlightFields()方法可以获取所有高亮显示的字段及其对应的高亮显示结果的映射,结构为Map形式。当获取到某字段对应的高亮显示结果后,可以通过HighlightField.getFragments()方法获取结果的Text数组形式,后续进行遍历取出即可
    ES中进行纠错匹配时使用fuzzy-match搜索
    match查询支持模糊匹配,这里的模糊匹配指的是ES将查询文本进行分词进而得到分词列表,然后将列表中的词语分别和索引中的词语进行匹配,这时按照编辑距离进行模糊匹配,在符合编辑距离阈值的情况下才算是匹配 fuzziness

    更精准的拼写纠错 拼音分析器设置中,设置拼音单字的首字母和拼音组合的首字母全部不使用,只使用拼音单字的全拼形式。接着使用fuzzy-match和match_phrase进行联合查询
    文本搜索,ES默认使用BM25算法进行相关性计算
    TF-IDF=TF·IDF TF-IDF(Term Frequency-Inverse Document Frequency,词频-逆文档频率)是文本挖掘和信息检索工作中数据处理的常用加权技术之一,主要作用是评估词语在文档中的重要程度。
    B25算法中 一般来说,文档如果足够短,则其分值应该更高
    boost值的设置只限定在term查询和类match查询中,其他类型的查询不能使用boost设置。boost值没有特别约束,因为它代表的是一个相对值。当该值在0~1时表示对权重起负向作用,当该值大于1时表示对权重起正向作用。
    Java客户端中使用boost参数时,只需要在QueryBuilder实例中调用boost()方法即可
    ES的boosting查询可用来term查询和类match查询之外的权重调整,分为两部分,一部分是positive查询,代表正向查询,另一部分是negative查询,代表负向查询。可以通过negative_boost参数设置负向查询的权重系数,该值的范围为0~1。最终的文档得分为:正向匹配值+负向匹配值×negative_boost
    Java客户端中可以使用QueryBuilders.boostingQuery()方法构建BoostingQueryBuilder的实例对象
    Function Score查询模式,用户可以借助该查询模式使用多种因素来影响打分逻辑
    random_score随机函数对文档进行打分
    script_score函数,它支持用户使用脚本自定义评分函数 结果必须大于或者等于0,不能为负数,否则,ES将会报错
    weight函数提供的是一个系数,最终的得分等于对原有评分乘以这个系数
    字段值因子函数field_value_factor,该函数可以省去编写脚本代码的麻烦
    score_mode的默认值为multiply 还有sum avg first max min
    Function Score查询中使用衰减函数 gauss、linear和exp
    使用衰减函数时,可以设定如下参数:·origin:用于设定计算距离的原点,该参数的值必须和字段类型相对应。·offset:用于设定距离原点多远范围内的数据将享有和原点一样的衰减值,其默认值为0。·scale:衰减曲线的一个锚点,即定义到该点的值,其衰减的值为某个值(即为decay的值)。这个锚点横坐标值的定义为原点+offset+scale,纵坐标为decay参数的值。·decay:和scale配套使用,用于设定锚点的纵坐标,即衰减值,其默认值为0.5。
    Script Score默认的脚本语言为Painless cript Score查询中的脚本代码必须有返回值并且类型为数值型,如果没有返回值,则Script Score查询默认返回0
    例如 GET /hotel/_search { “query”: { “script_score”: { “query”: { //查询特定文档 “match”: { “title”: “金都” } }, “script”: { “source”: “def a=1;def b=2;return a+b;” //使用脚本进行打分 } } } }
    如果字段属于基本数据类型,则可以通过params._source. f i e l d n a m e 获取字段的值 , 也可以使用 d o c [ ′ field_name获取字段的值,也可以使用doc[' fieldname获取字段的值,也可以使用doc[field’]来引用字段,使用doc[‘$field’].value引用字段的值
    访问object类型字段中的值时,除了使用“.”操作符引用该object类型的字段外,对其他字段的访问与访问索引的普通字段类似
    saturation,顾名思义,它是计算饱和度的函数,其实相当于计算占比
    sigmoid函数在处理数值型数据时将其值的变换值映射到0~1
    ScriptScoreQueryBuilder
    默认情况下,当存在二次打分时,文档的得分为:原始查询分数+二次打分分数。而用户可以为这两部分的分数设置权重,所以文档得分为:原始查询分数×原始查询权重+二次打分分数×二次打分权重。
    可以分别设置query_weight和rescore_query_weight,为原始查询权重和二次打分权重赋值
    Java客户端中,需要为searchSourceBuilder对象添加QueryRescorerBuilder对象才能进行二次打分
    ES支持丰富的聚合操作,不仅可以使用聚合功能对文档进行计数,还可以计算文档字段的平均值、最大值和最小值等。ES还提供了桶聚合的功能,以便于对多维度数据进行聚合 AggregationBuilders
    stats聚合可以将对应字段的最大值、最小值、平均值及加和值一起计算并返回计算结果
    value_count聚合,该聚合用于统计字段非空值的个数 missing参数指定填充值对空值进行填充-即默认值
    按多维度聚合 就是桶聚合
    聚合的桶也需要匹配,匹配的方式有terms、filter和ranges等 TermsAggregationBuilder AggregationBuilders sumAggregationBuilder RangeAggregationBuilder GeoDistanceAggregationBuilder AvgAggregationBuilder
    桶字段类型不是keyword类型,ES在聚合时会将桶字段转换为Lucene存储的实际值进行识别
    直接聚合 先查询再聚合

    前过滤器 聚合条件进一步地过滤,但是又不能影响当前的查询条件 则可以在aggs中使用filter FilterAggregationBuilder
    后过滤器 post_filter searchSourceBuilder.postFilter BucketOrder
    Top hits聚合和Collapse聚合,并分别给出这两种查询的分页方案 agges中指定total_hits
    TopHitsAggregationBuilder

    与Top hits聚合不同,Collapse聚合的结果是封装在hit中的 CollapseBuilder

    搜索建议的需求主要关注两点,即匹配和排序。匹配即能够通过用户的输入进行前缀匹配,给出匹配的搜索热词。用户的输入分为3种,即根据汉字输入、根据拼音全拼输入和根据拼音的首字母输入。排序即根据建议词的优先级进行排序,排序的优先级按照汉字输入匹配、拼音全拼输入匹配和拼音的首字母输入匹配逐次递减。

    后端需要将用户搜索日志收集在一起,以供搜索建议等模块使用 如果数据量比较大,还需要用到Hadoop等分布式存储服务。
    Canal、Flume和Hadoop等组件,这些组件是搜索引擎服务中不可或缺的部分,因为它们和搜索的主服务一起构成了数据的流通闭环
    Canal是阿里巴巴开源的监听Binlog日志的组件,它实现了MySQL Slave与MySQL Master之间的通信协议,将自己伪装成MySQL Slave,从而获取和解析Binlog日志。对于解析结果的存储,Canal提供了很多对接方案,用户可选择配置Kafka、HBase、ES等存储组件
    Flume是一种高可用、高并发、分布式的数据传输系统,它不仅具有故障转移和恢复机制,而且具有一定的健壮性和容错性。借助Flume,用户可以在多种日志场景中定义数据的输入端和输出端 通过Flume可以将业务日志传输到HDFS中。Flume可用于传输大量事件数据,如行为日志、图像信息流等,因此业界一般都用它来完成数据的汇总工作。
    Hadoop是一个分布式系统基础架构。用户可以使用Hadoop提供的开发接口开发分布式程序,也可以使用其生态圈中的Hive进行SQL的数据开发。
    从Hadoop中获取用户搜索日志后 统计每个搜索关键字的搜索次数 ,统计的数值将作为suggest匹配后的排序权重,最后由初始化程序将处理的结果存入ES中。
    只有将字段类型设置为completion,该字段才能作为suggest查询字段进行使用。

  • 相关阅读:
    单调栈leetcode.907
    【微信小程序】页面返回且带回数据
    .net 温故知新【13】:Asp.Net Core WebAPI 使用依赖注入DI
    北斗网络时钟服务器(北斗卫星授时服务器)应用方案
    IP地址欺骗的危害与后果
    如何把.mhd和.raw文件转换为DICOM文件
    Spring boot使用websocket实现在线聊天
    MATLAB学习
    Linux 命令(195)—— dhclient 命令
    气人|这种通过率调优技巧居然这么晚才让我知道
  • 原文地址:https://blog.csdn.net/lonsonlee/article/details/126709522