当前位置: 首页 > 后端技术 > Java

全文搜索Elasticsearch入门,看完这篇文章就够了

时间:2023-04-01 20:09:11 Java

一、elasticsearch简介1、背景在订单管理系统中,订单查询的调用量非常大。如果直接查询数据库,数据库的压力可想而知。而且有时候需要执行一些复杂的查询,sqlfriendly无法支持,需要查询很多表。再比如,如果用户输入的关键字错误或者有错别字,用sql是查不到的。所以打算用Elasticsearch来承载订单查询的主要压力。总的来说,使用elasticsearch(以下简称es)的原因有以下几点:关系型数据库在进行模糊(%keyword%)搜索时,会扫描整张表,查询速度非常慢。不支持全文分词搜索。例如,用户想搜索:公众号-珍虾,结果搜索错了:公众号-珍虾。es可以根据分词结果搜索到想要的结果。es2和es的基本概念用于数据分析和日志分析Elasticsearch是一个分布式的、RESTful风格的搜索和数据分析引擎,适用于文本、数字、地理空间、结构化和非结构化数据等所有类型的数据。Elasticsearch基于ApacheLucene开发,并于2010年由ElasticsearchN.V.(现为Elastic)首次发布。Elasticsearch是文件存储,Elasticsearch是面向文档的数据库。这里的一条数据就是一个文档,使用JSON作为文档序列化格式。比如下面的用户数据:{"name":"甄大虾","sex":0,"age":24}3.es的分布式优势:横向扩展,添加服务器可以直接配置在集群中高availability:提供复制功能,具有容错机制,可以自动发现新的或失效的节点,Reorganizeandrebalancenodedatareal-time:数据进入es,可以实现接近实时的搜索Restfulapi:RESTful风格的全文搜索injson格式:基于lucene强大的全文搜索能力4.使用场景全文搜索当我们使用百度搜索,谷歌搜索时,输入关键词搜索最相关的文章,这就是使用强大的全文es的搜索能力。好处:如果一个索引的数据量很大,会造成硬盘和搜索速度的瓶颈。分片可以分担压力。Sharding允许我们执行水平分割和扩展容量。可以在多个分片上执行分布式和并行操作。提高系统吞吐量注意:primaryshard创建后不能修改,但replica可以随时修改。如果要修改primaryshards的个数怎么办?删除并重建。"settings":{"number_of_shards":2,//主分片"number_of_replicas":1//从主分片复制副本(Replicas),提供高可用的好处:高可用,当一个主分片挂了,副本可以替换工作副本,也可以执行搜索操作。一个分散主分片(Cluster)压力的集群由一个或多个节点组成。只有具有相同集群名称的节点才能形成集群。它们一起保存全部数据,并一起提供索引和搜索功能。注意:primaryshard和copy在不同的node上,所以当primaryshard的机器挂了,copy不会受到影响,因为在不同的机器上,copy会继续作为primaryshard工作。因此,es的最低高可用配置是两个服务器节点(nodes)。单个es实例称为节点(node),节点是集群中的服务器,作为集群的一部分存储数据。Type(类型)7.x去掉了type,8.x会彻底去掉image-202109201838048252.索引原理es使用的是倒排索引,也叫反向索引。既然有倒排索引,那有没有正排呢?指数,对,我们先介绍正指数。1、正向索引正向索引以文档的ID为key,文档中各个字段的值为value。主要场景是通过id获取文档信息。常用的msyql关系型数据库就是这样查询的。比如id内容1mynameiszhendaxia2mynameisjack可以通过id快速查询内容,但是查询name之类的时候需要用like,数据量大的时候查询时间很长而且不能满足快速查询的要求。2.倒排索引倒排索引是用词或词作为关键词进行索引,记录这个关键词出现的文档的ID。比如上面的例子使用倒排索引如下:contentdocidmy1,2name1,2is1,2zhendaxia1jack2倒排索引,通过word或word快速查找所有文档的id,根据文档id快速查找内容。由于人类词汇的数量相对有限且固定,因此未来关键字的增加不会对效率产生太大影响。三、集群扩容1、集群健康image-20210920221154778集群有三种健康状态:绿绿、黄黄、红红绿色(健康):所有主从分片都正常运行黄色(亚健康):所有的主分片正常运行,但一些次分片运行不正常。红色(不健康):主分片运行不正常。2.扩容一般分为纵向和横向两种1).好的服务器代替原来的服务器,但是不推荐这种扩容,毕竟单机性能总是有瓶颈的2)、水平扩容Horizo??ntalexpansion也叫水平扩容,就是增加服务器的数量服务器。共同构成强大的计算能力。俗话说:团结就是力量。4.浏览器插件头插件是ES的可视化插件,类似于navicat和mysql的关系。head插件是一个web前端展示插件,用于浏览和交互ES数据,也是一个监控ES状态的客户端插件。首先,让我们看一下文本和关键字之间的区别。text:可分词,用户可全文搜索,可模糊匹配搜索keyword:不可分词,可搜索关键词,整体只能搜索某个值。type是text,但是有fields-keyword:这个type,一个是自己加的,一个是es插入数据的时候还没有创建字段english\_name。这时候es会自动根据数据类型为你创建一个字段。如果是string类型,由于无法判断你的string是用于精确查询还是模糊查询,es会创建一个text类型,支持模糊查询,同时会创建字段,类型为keyword,并且支持精准查询,所以当你要精准查询的时候,字段名不是原来的english\_name,而是以english\_name.keyword为例说明,首先插入下面的数据,keywordzhen{"text_name":"甄大侠","keyword_name":"甄大侠","english_name":"甄大侠","age":18,"classId":2,"score":90,"createTime":1629353892784}查询文本\_名称。由于text\_name的类型是text,所以zhendaxia的分词会是zhen和daxia。所以用zhen查询的时候可以匹配到zhen,所以会有返回结果。如何查看zhen大侠分了哪些词,可以使用GETyourindex/\_doc/dataid/\_termvectors?fields=fieldname,比如我的索引是test-user,语句是:GETtest-user/\_doc/1/\_termvectors?fields=text\_nameGETtest-user/_search{"query":{"term":{"text_name":{"value":"zhen"}}}}image-20210920232241959查询关键字\_name,因为keyword\_name的类型是关键字,不会分词,所以zhen无法搜索数据_name,没有找到我的结果法师202109202339279602。添加映射字段PUT/index/_mapping{"properties":{"keyword-name":{"type":"keyword"}}}3.查询GETtest-user/_search3.1match(全文搜索)full-文本搜索,分词,模糊查询,比如关键字zhendaxia,会被拆分成zhen,daxia{"query":{"match":{"text_name":"zhendaxia"}}}springboot方法boolQueryBuilder。filter(QueryBuilders.matchQuery("text_name","甄大侠"));3.2term(accuratequery)精准查询,不会分词,比如关键字zhendaxia,会直接使用zhendaxia来搜索{"query":{"term":{"keyword_name":{"value":"zhendaxia"}}}}springboot方法QueryBuilders.termQuery("keyword_name","zhendaxia");3.3terms(多值匹配)和termquery一样,但是它允许你指定多个值进行匹配,如果这个字段包含指定的任意一个值,那么就认为该文档满足条件类似mysql的in{"query":{"terms":{"keyword_name":["zhen","daxia"]}}}springboot方法QueryBuilders.termsQuery("keyword_name",Lists.newArrayList("zhen","daxia"));3.4range(rangequery)范围查询,比如查找大于等于20小于等于30的数据{"query":{"range":{"age":{"gte":20,#大于等于大于使用gt"lte":30#小于等于小于使用lt}}}}}springboot方法RangeQueryBuilderrangeQueryBuilder=QueryBuilders.rangeQuery("age");rangeQueryBuilder.gte(20);rangeQueryBuilder.lte(30)(Prefixquery)前缀查询,比如搜索zhen,前缀是zhen就会被搜索{"query":{"prefix":{"keyword_name":{"value":"zhen"}}}}springboot方法QueryBuilders.prefixQuery("keyword_name","zhen");3.6wildcard(wildcardfuzzyquery)通配符模糊查询,类似mysql之类的,?匹配一个字符,*匹配0~n个字符{"query":{"wildcard":{"keyword_name":{"value":"*prawn"}}}}*prawn")3.7fuzzy(模糊查询,不精确查询)不同于mysql之类的,它有些词可能会错,比如搜索mock,可以搜索mick{"query":{"fuzzy":{"keyword_name":"mock"}}}springbootmethodQueryBuilders.fuzzyQuery("keyword_name","嘲笑”);3.8must,mustnot,should//must:必须boolQueryBuilder.must(QueryBuilders.termQuery("keyword_name","mick"));//mustnot:notboolQueryBuilder.mustNot(QueryBuilders.termQuery("keyword_name","mick")"));//should:类似于mysql或者boolQueryBuilder.should(QueryBuilders.termQuery("keyword_name","jack"));boolQueryBuilder.should(QueryBuilders.termQuery("keyword_name","mick"));3.9匹配all(查询全部)查询全部,默认10SearchSourceBuildersourceBuilder=newSearchSourceBuilder();MatchAllQueryBuildermatchAllQueryBuilder=QueryBuilders.matchAllQuery();sourceBuilder.query(matchAllQueryBuilder);sourceBuilder.size(10);3.10match\_phrase查询的字段也匹配分词后所有关键词的顺序。例如下面的数据:1.keyword_name:zhendaxia2.keyword_name:daxiazhen3.keyword_name:我是甄大侠4。3、2:顺序错误,4:所有分词都不匹配可以通过slp因子调整,比如1,少一个匹配也满足{"query":{"match_phrase":{"keyword_name":{"query":"zhendaxia","slop":1}}}}3.11multi\_match(多字段匹配)multi-field匹配,如果有字段匹配就满足,keyword\_name=jack,或者english\_name=jack,满足就算了{"query":{"multi_match":{"query":"jack","fields":["keyword_name","english_name"]}}}j3.12filter和must(过滤)filter和must属于同一级别的查询方法,两者都可以作为query->bool属性过滤器:不计算分值,查询效率高;带缓存(推荐)必须:要计算分值,查询效率低;无缓存3.13聚合查询(aggregation)groupbynamebuilder.aggregation(AggregationBuilders.terms("agg").field("keyword_name").size(10));关注公众号:甄大虾,分享更多java后台-完结干货你们的支持是对我不断创作的莫大鼓励,下期见

猜你喜欢