Gitee地址:https://gitee.com/yuyuuyuy/micro-mall
文章目录
搜索是互联网各个项目中的常见场景,而Elasticsearch就是搜索领域最重要的工具之一,它基于倒排索引,天然支持全文搜索,且搜索效率极高。而且支持分布式,可横向拓展。具有存储,搜索,分析功能。总的来说,you know,for search.
根据官网,ES具有存储,搜索,分析三大功能,本文也按这三大功能展开。
1.存储
ES版本跟新较快,且变化较大,新的版本里已经没有类型这一概念了。
新建产品索引实例如下,其中type指的是字段类型,keyword不支持分词,text支持分词,analyzer可设置分词的粒度,index表示是否建立该字段的索引,doc_values表明是否支持对该字段的聚合分析。该例子中图片就是一长串的url,没有搜索价值,也没有分析价值,所以这两个值都设为false节省空间。
PUT product
{
"mappings": {
"properties": {
"skuId":{
"type": "long"
},
"spuId":{
"type": "keyword"
},
"skuTitle":{
"type": "text",
"analyzer": "standard"
},
"brandImg":{
"type": "keyword",
"index": false,
"doc_values": false
}
}
}
}
}
}
}
如果要插入数据,只用以json格式插入数据即可
比如
PUT product/1
{
"name":"手机",
"price":"3000"
}
有些情况下ES的数据是从mysql中同步的,这种情况一般使用canal伪装成mysql的从机,监听binlog数据然后同步到ES,但是这种架构在并发量高的情况下可能会丢失数据,因此,cannel和ES之间还要加个消息队列
2.搜索
最简单的就是match语句,比如
"match": {
"title": "小米手机"
}
这里要注意的是,match是默认分词查询,比如小米手机,会分词成小米和手机两个词进行查询。如果不想分词查询,就想搜小米手机,那么就要用match_phrase,但是结果可以分词,比如你可能会搜到小米手机Pro11这样的结果。如果连搜索结果都不想分词,就要用term查询,这样搜小米手机,结果只能是小米手机 。总结:不想全文搜索的字段用term查询,想全文搜索的字段用match查询。
在基本查询的基础上,还有布尔查询,就是所有的查询条件都满足才返回结果。布尔查询有4种子句,分别是must,should,must_not,filter。must:必须满足must子句的条件,并且参与计算分值。should:满足任意一个即可,参与计算分值。must_not:必须不满足查询条件。filter:返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值。
3.聚合分析
就是在查询结果的基础上,对查询结果进行聚合分析。比如统计有哪些商家在卖搜索的商品,某价格区间内的商品有多少种等等。语法大概是聚合名称(自定义),聚合规则(大于小于,求平均值,统计聚合等),聚合字段(对哪个字段进行分析),并且在聚合的基础上,还可以嵌套聚合。
这是在kibana上使用DSL来构建查询语句

这里通过match全文搜索华为产品,并通过filter过滤出价格3000到4500的产品,最后通过aggs聚合分析出有两家商铺在卖华为产品。
使用elasticsearchRestTemplate进行查询

ES查询可用DSL查询,也可用ES给java提供的API:ElasticsearchRestTemplate来查询,而ElasticsearchRestTemplate只是DSL的映射而已。
创建索引:
PUT goods
{
"mappings": {
"properties": {
"id":{
"type": "long"
},
"title":{
"type": "text"
},
"img":{
"type": "keyword",
"index":"false",
"doc_values": false
},
"shop":{
"type": "keyword"
},
"price":{
"type": "keyword"
}
}
}
}
添加数据:
使用Jsoup爬虫自行添加,略
查询:
GET goods/_search
{
"query": {
"bool": {
"must": [
{"match": {
"title": "华为"
}}
],
"filter": [
{"range": {
"price": {
"gte": 3000,
"lte": 4500
}
}}
]
}
},
"aggs": {
"店铺": {
"terms": {
"field": "shop",
"size": 10
}
}
}
}
查询:全文搜索商品名称,指定产品价格范围,分析出有哪些店铺在卖该商品
GET goods/_search
{
"query": {
"bool": {
"must": [
{"match": {
"title": "华为"
}}
],
"filter": [
{"range": {
"price": {
"gte": 3000,
"lte": 4500
}
}}
]
}
},
"aggs": {
"店铺": {
"terms": {
"field": "shop",
"size": 10
}
}
}
}
使用elasticsearchRestTemplate进行查询
public void search(String keyword, Integer pageNum, Integer pageSize) {
//构建原生查询
NativeSearchQueryBuilder nativeSearchQueryBuilder=new NativeSearchQueryBuilder();
// 构建布尔查询
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//构建普通查询,根据产品名称全文搜索
MatchQueryBuilder titleQuery = QueryBuilders.matchQuery("title", keyword);
//构建普通查询,过滤出在指定价格区间内的产品
RangeQueryBuilder price = QueryBuilders.rangeQuery("price");
//这里暂时先定义价格范围的默认值
price.gte(3000);
price.lte(5000);
//把普通查询放入布尔查询
boolQueryBuilder.must(titleQuery);
//布尔查询,把原生查询放入布尔查询种
boolQueryBuilder.filter(price);
//聚合分析出卖该产品的所有商铺
TermsAggregationBuilder shop= AggregationBuilders.terms("店铺").field("shop").size(10);
//将布尔查询放入原生查询
nativeSearchQueryBuilder.withQuery(boolQueryBuilder);
//将聚合查询放入原生查询
nativeSearchQueryBuilder.addAggregation(shop);
//设置分页参数
nativeSearchQueryBuilder.withPageable(PageRequest.of(pageNum, pageSize));
//执行原生查询,查看搜索结果
SearchHits<Content> searchs = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), Content.class);
for (SearchHit<Content> search:searchs
) {
System.out.println(search.getContent());
}
//查看聚合分析结果,有哪些商铺在卖这种产品
Aggregations aggregations = searchs.getAggregations();
Aggregation aggregation = aggregations.get("店铺");
List<? extends Terms.Bucket> buckets = ((ParsedStringTerms) aggregation).getBuckets();
for (Terms.Bucket bucket : buckets) {
// 获取商铺的集合
String key = (String) bucket.getKey();
System.out.println(key);
}
}
以上就是使用ElasticSearch进行查询的案例,核心是理解DSL语句的逻辑结构,然后就能很轻松地进行各种复杂的查询
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复
寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是rubygems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和rubygems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko
我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/
在ruby中,你可以这样做:classThingpublicdeff1puts"f1"endprivatedeff2puts"f2"endpublicdeff3puts"f3"endprivatedeff4puts"f4"endend现在f1和f3是公共(public)的,f2和f4是私有(private)的。内部发生了什么,允许您调用一个类方法,然后更改方法定义?我怎样才能实现相同的功能(表面上是创建我自己的java之类的注释)例如...classThingfundeff1puts"hey"endnotfundeff2puts"hey"endendfun和notfun将更改以下函数定