最新要闻
- 2023春节新片预售票房破3000万:黑马杀出 《流浪地球2》仅排第三
- 今日看点:荣耀首款小折叠屏来了:5千档真香
- 世界信息:今晚8点播出 王冰冰、撒贝宁等人组团剧透央视网络春晚
- 3999元解决安卓四大不可能 一加11成酷安最热机型:领先第二名一倍
- 张朝阳称年轻人不要只追求赚钱和快乐:想法不对 你会很痛苦 本人风趣回应
- 当前热讯:网易开始解散暴雪游戏相关团队!分手已成定局
- 世界微头条丨特斯拉海外大降价 美国新车主:恶心、不愿再看一眼爱车
- 全球快消息!门票值了!大熊猫看到游客后展示“才艺”:抱着竹子连续翻跟头
- 省钱还是抠门?马斯克不交房租:员工在工作日被房东赶出
- 环球视点!微信将处理假冒仿冒官方组织公众号:严重违规直接删号
- 全体起立!马自达MX-30 R-EV官图发布:转子发动机回归
- 全球要闻:雷军晒奖杯:《小米创业思考》获2022豆瓣年度大奖 揭秘小米创业经历
- 和女神视频聊天再也不害羞了!NVIDIA新技术让你“暗送秋波”:画面以假乱真
- 今日热讯:新娘刚下婚车遭痱子粉迎面砸脸引网友热议:婚闹是素质缺乏没教养?
- 当前讯息:“爱妻”来了!理想L7“皇后座”到底有多爽?1米2的腿部空间感受下
- 万元LV误标1599元被秒拍 得物回应:多次确认无异 无权干预
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
世界播报:使用 Elasticsearch 搭建自己的搜索系统,这个厉害了。。
作者:Hai Xiang 来源:https://www.cnblogs.com/haixiang/p/12867160.html
(相关资料图)
什么是elasticsearch
Elasticsearch 是一个开源的高度可扩展的全文搜索和分析引擎,拥有查询近实时的超强性能。
大名鼎鼎的Lucene 搜索引擎被广泛用于搜索领域,但是操作复杂繁琐,总是让开发者敬而远之。而 Elasticsearch将 Lucene 作为其核心来实现所有索引和搜索的功能,通过简单的 RESTful 语法来隐藏掉 Lucene 的复杂性,从而让全文搜索变得简单
ES在Lucene基础上,提供了一些分布式的实现:集群,分片,复制等。
搜索为什么不用MySQL而用es
我们本文案例是一个迷你商品搜索系统,为什么不考虑使用MySQL来实现搜索功能呢?原因如下:
- MySQL默认使用innodb引擎,底层采用b+树的方式来实现,而Es底层使用倒排索引的方式实现,使用倒排索引支持各种维度的分词,可以掌控不同粒度的搜索需求。(MYSQL8版本也支持了全文检索,使用倒排索引实现,有兴趣可以去看看两者的差别)
- 如果使用MySQL的
%key%
的模糊匹配来与es的搜索进行比较,在8万数据量时他们的耗时已经达到40:1左右,毫无疑问在速度方面es完胜。
es在大厂中的应用情况
- es运用最广泛的是elk组合来对日志进行搜索分析
- 58安全部门、京东订单中心几乎全采用es来完成相关信息的存储与检索
- es在tob的项目中也用于各种检索与分析
- 在c端产品中,企业通常自己基于Lucene封装自己的搜索系统,为了适配公司营销战略、推荐系统等会有更多定制化的搜索需求
es客户端选型
spring-boot-starter-data-elasticsearch
我相信你看到的网上各类公开课视频或者小项目均推荐使用这款springboot整合过的es客户端,但是我们要say no!
另外,ES 系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。
此图是引入的最新版本的依赖,我们可以看到它所使用的es-high-client也为6.8.7,而es7.x版本都已经更新很久了,这里许多新特性都无法使用,所以版本滞后是他最大的问题。而且它的底层也是highclient,我们操作highclient可以更灵活。我呆过的两个公司均未采用此客户端。
elasticsearch-rest-high-level-client
这是官方推荐的客户端,支持最新的es,其实使用起来也很便利,因为是官方推荐所以在特性的操作上肯定优于前者。而且该客户端与TransportClient不同,不存在并发瓶颈的问题,官方首推,必为精品!
搭建自己的迷你搜索系统
引入es相关依赖,除此之外需引入springboot-web依赖、jackson依赖以及lombok依赖等。
Spring Boot 基础就不介绍了,推荐下这个实战教程:https://www.javastack.cn/categories/Spring-Boot/
7.3.2 org.elasticsearch.client elasticsearch-rest-high-level-client ${es.version} org.elasticsearch.client elasticsearch-rest-client org.elasticsearch elasticsearch org.elasticsearch elasticsearch ${es.version} org.elasticsearch.client elasticsearch-rest-client ${es.version}
es配置文件es-config.properties
es.host=localhostes.port=9200es.token=es-tokenes.charset=UTF-8es.scheme=httpes.client.connectTimeOut=5000es.client.socketTimeout=15000
封装RestHighLevelClient
@Configuration@PropertySource("classpath:es-config.properties")public class RestHighLevelClientConfig { @Value("${es.host}") private String host; @Value("${es.port}") private int port; @Value("${es.scheme}") private String scheme; @Value("${es.token}") private String token; @Value("${es.charset}") private String charSet; @Value("${es.client.connectTimeOut}") private int connectTimeOut; @Value("${es.client.socketTimeout}") private int socketTimeout; @Bean public RestClientBuilder restClientBuilder() { RestClientBuilder restClientBuilder = RestClient.builder( new HttpHost(host, port, scheme) ); Header[] defaultHeaders = new Header[]{ new BasicHeader("Accept", "*/*"), new BasicHeader("Charset", charSet), //设置token 是为了安全 网关可以验证token来决定是否发起请求 我们这里只做象征性配置 new BasicHeader("E_TOKEN", token) }; restClientBuilder.setDefaultHeaders(defaultHeaders); restClientBuilder.setFailureListener(new RestClient.FailureListener(){ @Override public void onFailure(Node node) { System.out.println("监听某个es节点失败"); } }); restClientBuilder.setRequestConfigCallback(builder -> builder.setConnectTimeout(connectTimeOut).setSocketTimeout(socketTimeout)); return restClientBuilder; } @Bean public RestHighLevelClient restHighLevelClient(RestClientBuilder restClientBuilder) { return new RestHighLevelClient(restClientBuilder); }}
封装es常用操作es搜索系统封装源码
@Servicepublic class RestHighLevelClientService { @Autowired private RestHighLevelClient client; @Autowired private ObjectMapper mapper; /** * 创建索引 * @param indexName * @param settings * @param mapping * @return * @throws IOException */ public CreateIndexResponse createIndex(String indexName, String settings, String mapping) throws IOException { CreateIndexRequest request = new CreateIndexRequest(indexName); if (null != settings && !"".equals(settings)) { request.settings(settings, XContentType.JSON); } if (null != mapping && !"".equals(mapping)) { request.mapping(mapping, XContentType.JSON); } return client.indices().create(request, RequestOptions.DEFAULT); } /** * 判断 index 是否存在 */ public boolean indexExists(String indexName) throws IOException { GetIndexRequest request = new GetIndexRequest(indexName); return client.indices().exists(request, RequestOptions.DEFAULT); } /** * 搜索 */ public SearchResponse search(String field, String key, String rangeField, String from, String to,String termField, String termVal, String ... indexNames) throws IOException{ SearchRequest request = new SearchRequest(indexNames); SearchSourceBuilder builder = new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolQueryBuilder.must(new MatchQueryBuilder(field, key)).must(new RangeQueryBuilder(rangeField).from(from).to(to)).must(new TermQueryBuilder(termField, termVal)); builder.query(boolQueryBuilder); request.source(builder); log.info("[搜索语句为:{}]",request.source().toString()); return client.search(request, RequestOptions.DEFAULT); } /** * 批量导入 * @param indexName * @param isAutoId 使用自动id 还是使用传入对象的id * @param source * @return * @throws IOException */ public BulkResponse importAll(String indexName, boolean isAutoId, String source) throws IOException{ if (0 == source.length()){ //todo 抛出异常 导入数据为空 } BulkRequest request = new BulkRequest(); JsonNode jsonNode = mapper.readTree(source); if (jsonNode.isArray()) { for (JsonNode node : jsonNode) { if (isAutoId) { request.add(new IndexRequest(indexName).source(node.asText(), XContentType.JSON)); } else { request.add(new IndexRequest(indexName) .id(node.get("id").asText()) .source(node.asText(), XContentType.JSON)); } } } return client.bulk(request, RequestOptions.DEFAULT); }
创建索引,这里的settings是设置索引是否设置复制节点、设置分片个数,mappings就和数据库中的表结构一样,用来指定各个字段的类型,同时也可以设置字段是否分词(我们这里使用ik中文分词器)、采用什么分词方式。
@Testpublic void createIdx() throws IOException { String settings = "" + " {\n" + " \"number_of_shards\" : \"2\",\n" + " \"number_of_replicas\" : \"0\"\n" + " }"; String mappings = "" + "{\n" + " \"properties\": {\n" + " \"itemId\" : {\n" + " \"type\": \"keyword\",\n" + " \"ignore_above\": 64\n" + " },\n" + " \"urlId\" : {\n" + " \"type\": \"keyword\",\n" + " \"ignore_above\": 64\n" + " },\n" + " \"sellAddress\" : {\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\", \n" + " \"search_analyzer\": \"ik_smart\",\n" + " \"fields\": {\n" + " \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" + " }\n" + " },\n" + " \"courierFee\" : {\n" + " \"type\": \"text\n" + " },\n" + " \"promotions\" : {\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\", \n" + " \"search_analyzer\": \"ik_smart\",\n" + " \"fields\": {\n" + " \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" + " }\n" + " },\n" + " \"originalPrice\" : {\n" + " \"type\": \"keyword\",\n" + " \"ignore_above\": 64\n" + " },\n" + " \"startTime\" : {\n" + " \"type\": \"date\",\n" + " \"format\": \"yyyy-MM-dd HH:mm:ss\"\n" + " },\n" + " \"endTime\" : {\n" + " \"type\": \"date\",\n" + " \"format\": \"yyyy-MM-dd HH:mm:ss\"\n" + " },\n" + " \"title\" : {\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\", \n" + " \"search_analyzer\": \"ik_smart\",\n" + " \"fields\": {\n" + " \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" + " }\n" + " },\n" + " \"serviceGuarantee\" : {\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\", \n" + " \"search_analyzer\": \"ik_smart\",\n" + " \"fields\": {\n" + " \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" + " }\n" + " },\n" + " \"venue\" : {\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\", \n" + " \"search_analyzer\": \"ik_smart\",\n" + " \"fields\": {\n" + " \"keyword\" : {\"ignore_above\" : 256, \"type\" : \"keyword\"}\n" + " }\n" + " },\n" + " \"currentPrice\" : {\n" + " \"type\": \"keyword\",\n" + " \"ignore_above\": 64\n" + " }\n" + " }\n" + "}"; clientService.createIndex("idx_item", settings, mappings);}
分词技巧:
- 索引时最小分词,搜索时最大分词,例如"Java知音"索引时分词包含Java、知音、音、知等,最小粒度分词可以让我们匹配更多的检索需求,但是我们搜索时应该设置最大分词,用“Java”和“知音”去匹配索引库,得到的结果更贴近我们的目的,
- 对分词字段同时也设置keyword,便于后续排查错误时可以精确匹配搜索,快速定位。
我们向es导入十万条淘宝双11活动数据作为我们的样本数据,数据结构如下所示
{"_id": "https://detail.tmall.com/item.htm?id=538528948719\u0026skuId=3216546934499","卖家地址": "上海","快递费": "运费: 0.00元","优惠活动": "满199减10,满299减30,满499减60,可跨店","商品ID": "538528948719","原价": "2290.00","活动开始时间": "2016-11-11 00:00:00","活动结束时间": "2016-11-11 23:59:59","标题": "【天猫海外直营】 ReFa CARAT RAY 黎珐 双球滚轮波光美容仪","服务保障": "正品保证;赠运费险;极速退款;七天退换","会场": "进口尖货","现价": "1950.00"}
调用上面封装的批量导入方法进行导入
@Testpublic void importAll() throws IOException { clientService.importAll("idx_item", true, itemService.getItemsJson());}
我们调用封装的搜索方法进行搜索,搜索产地为武汉、价格在11-149之间的相关酒产品,这与我们淘宝中设置筛选条件搜索商品操作一致。
@Testpublic void search() throws IOException { SearchResponse search = clientService.search("title", "酒", "currentPrice", "11", "149", "sellAddress", "武汉"); SearchHits hits = search.getHits(); SearchHit[] hits1 = hits.getHits(); for (SearchHit documentFields : hits1) { System.out.println( documentFields.getSourceAsString()); }}
我们得到以下搜索结果,其中_score为某一项的得分,商品就是按照它来排序。
{ "_index": "idx_item", "_type": "_doc", "_id": "Rw3G7HEBDGgXwwHKFPCb", "_score": 10.995819, "_source": { "itemId": "525033055044", "urlId": "https://detail.tmall.com/item.htm?id=525033055044&skuId=def", "sellAddress": "湖北武汉", "courierFee": "快递: 0.00", "promotions": "满199减10,满299减30,满499减60,可跨店", "originalPrice": "3768.00", "startTime": "2016-11-01 00:00:00", "endTime": "2016-11-11 23:59:59", "title": "酒嗨酒 西班牙原瓶原装进口红酒蒙德干红葡萄酒6只装整箱送酒具", "serviceGuarantee": "破损包退;正品保证;公益宝贝;不支持7天退换;极速退款", "venue": "食品主会场", "currentPrice": "151.00" }}
扩展性思考
- 商品搜索权重扩展,我们可以利用多种收费方式智能为不同店家提供增加权重,增加曝光度适应自身的营销策略。同时我们经常发现淘宝搜索前列的商品许多为我们之前查看过的商品,这是通过记录用户行为,跑模型等方式智能为这些商品增加权重。
- 分词扩展,也许因为某些商品的特殊性,我们可以自定义扩展分词字典,更精准、人性化的搜索。
- 高亮功能,es提供highlight高亮功能,我们在淘宝上看到的商品展示中对搜索关键字高亮,就是通过这种方式来实现。
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2022最新版)
2.劲爆!Java 协程要来了。。。
3.Spring Boot 2.x 教程,太全了!
4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
-
世界播报:使用 Elasticsearch 搭建自己的搜索系统,这个厉害了。。
作者:HaiXiang来源:https: www cnblogs com haixiang p 12867160 html什么是elasticsearchElasticsearch是一个开
来源: 世界播报:使用 Elasticsearch 搭建自己的搜索系统,这个厉害了。。
理解宏定义
2023春节新片预售票房破3000万:黑马杀出 《流浪地球2》仅排第三
数字化“乡村小道”跑得不舒服,试试低代码“高速公路”
当前看点!一位民办二本学生的年终总结
今日看点:荣耀首款小折叠屏来了:5千档真香
世界信息:今晚8点播出 王冰冰、撒贝宁等人组团剧透央视网络春晚
3999元解决安卓四大不可能 一加11成酷安最热机型:领先第二名一倍
认识Java语言
读编程与类型系统笔记07_子类型
张朝阳称年轻人不要只追求赚钱和快乐:想法不对 你会很痛苦 本人风趣回应
当前热讯:网易开始解散暴雪游戏相关团队!分手已成定局
世界微头条丨特斯拉海外大降价 美国新车主:恶心、不愿再看一眼爱车
全球快消息!门票值了!大熊猫看到游客后展示“才艺”:抱着竹子连续翻跟头
省钱还是抠门?马斯克不交房租:员工在工作日被房东赶出
当前视点!Netty-核心模块组件-4
环球视点!微信将处理假冒仿冒官方组织公众号:严重违规直接删号
全体起立!马自达MX-30 R-EV官图发布:转子发动机回归
全球要闻:雷军晒奖杯:《小米创业思考》获2022豆瓣年度大奖 揭秘小米创业经历
和女神视频聊天再也不害羞了!NVIDIA新技术让你“暗送秋波”:画面以假乱真
今日热讯:新娘刚下婚车遭痱子粉迎面砸脸引网友热议:婚闹是素质缺乏没教养?
当前讯息:“爱妻”来了!理想L7“皇后座”到底有多爽?1米2的腿部空间感受下
万元LV误标1599元被秒拍 得物回应:多次确认无异 无权干预
ruoyi打包jar分离配置部署
环球热消息:今晚8点见!2023央视网络春晚节目单发布:王心凌、董宇辉首次加盟
数论笔记-同余
“背菜女孩”家人回应1年赚20万 不穷:虚构捏造博眼球视频获流量应被整治
每日简讯:国铁西安局回应火车内设麻将桌:系主题定制列车 还有KTV、影院
【焦点热闻】苹果1200万像素为何胜过安卓1亿像素?历代iPhone相机揭秘:果然是神优化
记好这24个ES6方法,用于解决实际开发的JS问题
C#、TS和Dart对比3:编译时常量和运行时常量
2023性能战神!卢伟冰:Redmi K60 Pro是用户追求性能的不二之选
环球要闻:卡梅隆发文diss漫威电影:超级英雄演的像大学生
【天天报资讯】集体涨价!Intel 13代酷睿8款新U开卖:65W 24核高达4889元
为什么人类很难准确预测未来?
全球快看点丨《和平精英》开枪时的振动:居然可以造福盲人
当前消息!模板-线段树
全球热点!算法学习笔记(8.1): 网络最大流算法 EK, Dinic, ISAP
学习笔记——Spring简介;Spring搭建步骤;Spring的特性;Spring中getBean三种方式;Spring中的标签
实时:AcWing257 关押罪犯
当前关注:使用vscode调试PHP底层C源码
特斯拉降价后:门店半小时售10台 老车主直呼被损失4万
焦点速读:特斯拉降价引海外热议:这是《孙子兵法》!欲消灭传统车企
你拿多少?报告称2022年终奖人均2.19万元 一线城市近3万元
环球今日讯!果香浓郁!徐福记DODO综合果味棒棒糖 60支19.9元
【世界速看料】保护隐私!微信键盘iOS 1.0.2版更新:体积膨胀到237MB
全球观天下!联想GeekPro 2023主机首销6199元起:13代i5+RTX 3060
【天天快播报】春节前最后一次成品油调价来了!或迎2023年首次降价
关注:畅想未来:2023年手机还能怎样进化?
对话郑刚:与罗永浩分歧关键不是商业利益
最野性的福特SUV!探险者Timberline亮相:超帅黑橙配色
33.58万起!比亚迪腾势D9成交付最快破万高端MPV
天天通讯!《魔兽世界》国服关闭倒计时!网易向玩家发短信安利《逆水寒》
从超前点映到480P投屏 视频平台赚钱只能靠“割韭菜”?
环球快消息!程序猿创造的AI虚拟漂亮老婆 被真女友强制“安乐死”了
天天热议:液金+水冷压住RTX 40系显卡:机械革命晒新旷世笔记本散热系统
特斯拉海外大降价!老外车主气炸请求维权:免费送FSD
环球关注:4K缩水到480p 爱奇艺称“有权变更内容” 律师回应称肯定违约了
环球讯息:《流浪地球2》发行通知公开:片长173分钟对标《阿凡达2》
时讯:网友铁了心要等一加11 Pro 李杰:没有11 Pro、11 Ultra
遭黑客广泛利用:微软无奈计划淘汰诊断工具MSDT
你涨工资没?全国招聘平均月薪增幅最高城市 最低1.2万、还在加薪
世界微速讯:曾两个月涨粉上千万!张同学回应热度消退:可以坦然面对
视点!小米6钉子户换上Redmi K50至尊版:速度就是快
马斯克突然调整Twitter API:第三方客户端全灭
不再是小仪表盘 新款比亚迪秦PLUS DM-i曝光:续航猛增至1310km
热点聚焦:燃油版“宏光MINIEV”!三菱Delica Mini首发:配0.66L发动机
【环球快播报】“蓝兔”邮票黄永玉有多潇洒?北京第一辆私家车拥有者 93岁开法拉利飙车
每日信息:三星将长焦发挥到极致!曝Galaxy S24 Ultra支持150倍变焦
快资讯:iPhone 14兔年限量保护套售价398元贵吗?部分型号卖断货
TP-LINK发布新款AX3000双频千兆Wi-Fi 6光口AP:支持DC、PoE双供电
世界微速讯:长白山人参旗舰店:全须生晒参4盒99元狂促(300元大额券)
播报:联想拯救者刃7000K 2023今日开售:i5-13400F+RTX3060 首发7199元
焦点热议:豆瓣9.5高分国漫!《中国奇谭》第二季已在筹备:要打造IP宇宙
最新快讯!二十六位朗读主播!讯飞有声书图赏
当前热讯:“1888万彩礼”事件作者承认编故事 知乎:永久封禁账号
热资讯!奇葩公司发大鹅当年货 员工开心又无奈:放公司很吵
天天微速讯:故意排放能怎样?日本决定核废水2023春夏排入海 多国网友愤怒
2022年动力电池装车量排名:“宁迪”双王吃下超7成市场
每日关注!73岁保安徒手接住4楼坠落女子获奖 网友:见义勇为、值得点赞
HarmonyOS智能座舱是怎样炼成的?华为官方揭秘软件开发标准
全球讯息:大手笔!蔚来官宣:春节高速路换电全免费、不限次数
今日最新!(六)elasticsearch 源码之选主流程分析
环球今日讯!java中关于继承,多态及方法调用的底层细节
如何构建基于 DDD 领域驱动的微服务?
世界新资讯:火山引擎 DataTester:一次 A/B 测试,帮助产品分享率提升超 20%
珠江的源头在哪里?珠江的长度是多少千米?
当前热文:被称作“电费刺客” 商家:踢脚线取暖器耗电量可达空调3倍
蜀国的皇帝有哪些?蜀国的皇帝列表排名
当前视点!明晚8点开播!央视网络春晚第二波阵容官宣:王心凌、撒贝宁等加盟
魔兽国服关闭当天 老外喜迎新版本升级 网友:暴雪杀人诛心
豆瓣9.2分神作!《新·福音战士剧场版:终》终于官宣引进
天天时讯:2023年电脑城奸商依然猖狂:3千元笔记本卖5千 出库不能退
为黛西小姐开车故事背景是什么?为黛西小姐开车故事梗概是什么?
打电动是什么意思?打电动是什么游戏?
特百惠是哪国的牌子?特百惠卖什么产品?
电视机顶盒怎么连接电视机?电视机顶盒怎么破解?
怎么给冰箱加氟?冰箱加氟一般需要多少钱?
excel怎么转化为在线表格?excel怎么转化为PDF?
lol怎么亮徽章?lol徽章有什么用?