赞
踩
Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。作为 Elastic Stack 的核心,Elasticsearch 会集中存储您的数据,让您飞快完成搜索,微调相关性,进行强大的分析,并轻松缩放规模。
下载Elasticsearch7.17.3版本的zip包,并解压到指定目录,下载地址:https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-17-3
安装中文分词器,注意下载与Elasticsearch对应的版本,下载地址
https://github.com/medcl/elasticsearch-analysis-ik/releases
下载完成后解压到Elasticsearch的plugins目录下
运行bin目录下的elasticsearch.bat启动Elasticsearch服务。
访问 http://localhost:9200/ 出现这个界面,表示启动成功
作为Elasticsearch 的客户端访问
下载Kibana,作为访问Elasticsearch的客户端,请下载7.17.3版本的zip包,并解压到指定目录,下载地址:https://www.elastic.co/cn/downloads/past-releases/kibana-7-17-3
运行bin目录下的kibana.bat,启动Kibana服务;
打开Kibana的用户界面,访问地址:http://localhost:5601
● Near Realtime(近实时):Elasticsearch是一个近乎实时的搜索平台,这意味着从索引文档到可搜索文档之间只有一个轻微的延迟(通常是一秒钟)。
● Cluster(集群):群集是一个或多个节点的集合,它们一起保存整个数据,并提供跨所有节点的联合索引和搜索功能。每个集群都有自己的唯一集群名称,节点通过名称加入集群。
● Node(节点):节点是指属于集群的单个Elasticsearch实例,存储数据并参与集群的索引和搜索功能。可以将节点配置为按集群名称加入特定集群,默认情况下,每个节点都设置为加入一个名为elasticsearch的群集。
● Index(索引):索引是一些具有相似特征的文档集合,类似于MySql中数据库的概念。
● Type(类型):类型是索引的逻辑类别分区,通常,为具有一组公共字段的文档类型,类似MySql中表的概念。注意:在Elasticsearch 6.0.0及更高的版本中,一个索引只能包含一个类型。
● Document(文档):文档是可被索引的基本信息单位,以JSON形式表示,类似于MySql中行记录的概念。
● Shards(分片):当索引存储大量数据时,可能会超出单个节点的硬件限制,为了解决这个问题,Elasticsearch提供了将索引细分为分片的概念。分片机制赋予了索引水平扩容的能力、并允许跨分片分发和并行化操作,从而提高性能和吞吐量。
● Replicas(副本):在可能出现故障的网络环境中,需要有一个故障切换机制,Elasticsearch提供了将索引的分片复制为一个或多个副本的功能,副本在某些节点失效的情况下提供高可用性。
通过Kibana的Dev Tools功能,我们可以操作Elasticsearch;
创建索引并查看
PUT /customer
GET /_cat/indices?v
删除索引并查看
DELETE /customer
GET /_cat/indices?v
首先要导入一批数据
https://github.com/macrozheng/mall-learning/blob/teach/document/json/accounts.json
POST /bank/account/_bulk
GET /bank/_mapping
PUT /customer/doc/1
{
"name": "John Doe"
}
GET /customer/doc/1
POST /customer/doc/1/_update
{
"doc": { "name": "Jane Doe" }
}
DELETE /customer/doc/1
查询表达式(Query DSL)是一种非常灵活又富有表现力的查询语言,Elasticsearch使用它可以以简单的JSON接口来实现丰富的搜索功能,下面的搜索操作都将使用它。
首先要导入一批数据
https://github.com/macrozheng/mall-learning/blob/teach/document/json/accounts.json
POST /bank/account/_bulk
最简单的搜索,使用match_all来表示,例如搜索全部
GET /bank/_search
{
"query": { "match_all": {} }
}
分页搜索,from表示偏移量,从0开始,size表示每页显示的数量
GET /bank/_search
{
"query": { "match_all": {} },
"from": 0,
"size": 10
}
搜索排序,使用sort表示,例如按balance字段降序排列;
GET /bank/_search
{
"query": { "match_all": {} },
"sort": { "balance": { "order": "desc" } }
}
搜索并返回指定字段内容,使用_source表示,例如只返回account_number和balance两个字段内容:
GET /bank/_search
{
"query": { "match_all": {} },
"_source": ["account_number", "balance"]
}
条件搜索,使用match表示匹配条件,例如搜索出account_number为20的文档
GET /bank/_search
{
"query": {
"match": {
"account_number": 20
}
}
}
短语匹配搜索,使用match_phrase表示,例如搜索address字段中同时包含mill和lane的文档:
GET /bank/_search
{
"query": {
"match_phrase": {
"address": "mill lane"
}
}
}
组合搜索,使用bool来进行组合,must表示同时满足,例如搜索address字段中同时包含mill和lane的文档;
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
组合搜索,should表示满足其中任意一个,搜索address字段中包含mill或者lane的文档;
GET /bank/_search
{
"query": {
"bool": {
"should": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
组合搜索,must_not表示同时不满足,例如搜索address字段中不包含mill且不包含lane的文档;
GET /bank/_search
{
"query": {
"bool": {
"must_not": [
{ "match": { "address": "mill" } },
{ "match": { "address": "lane" } }
]
}
}
}
组合搜索,组合must和must_not,例如搜索age字段等于40且state字段不包含ID的文档;
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
搜索过滤,使用filter来表示,例如过滤出balance字段在20000~30000的文档;
GET /bank/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } }
参考资料https://www.elastic.co/guide/en/elasticsearch/reference/7.17/getting-started.html
Spring Data Elasticsearch是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。
其中常用的FieldType类型有如下几种:
public enum FieldType { Auto("auto"), //自动判断字段类型 Text("text"), //会进行分词并建了索引的字符类型 Keyword("keyword"), //不会进行分词建立索引的类型 Long("long"), // Integer("integer"), // Short("short"), // Byte("byte"), // Double("double"), // Float("float"), // Date("date"), // Boolean("boolean"), // Object("object"), // Nested("nested"), //嵌套对象类型 Ip("ip"), // }
可以使用衍生查询,在接口中直接指定查询方法名称便可查询,无需进行实现,如商品表中有商品名称、标题和关键字,直接定义以下查询,就可以对这三个字段进行全文搜索。
/**
* @description 商品ES操作类
*/
public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
/**
* 搜索查询
*
* @param name 商品名称
* @param subTitle 商品标题
* @param keywords 商品关键字
* @param page 分页信息
* @return
*/
Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page);
}
通过@Query注解可以使用Elasticsearch的原生DSL语句进行查询;
/**
* @description 商品ES操作类
*/
public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
@Query("{"bool" : {"must" : {"field" : {"name" : " ? 0"}}}}")
Page<EsProduct> findByName(String name, Pageable pageable);
}
<!--Elasticsearch相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
spring:
data:
elasticsearch:
repositories:
enabled: true # 开启ES仓库配置,自动为仓库接口生成实现类
elasticsearch:
uris: http://localhost:9200 # ES的连接地址及端口号
不需要中文分词的字段设置成Keyword类型,需要中文分词的设置成Text类型,并设置分词器为ik_max_word;
/** * @description 搜索商品的信息 */ @Data @EqualsAndHashCode @Document(indexName = "pms") @Setting(shards = 1,replicas = 0) public class EsProduct implements Serializable { private static final long serialVersionUID = -1L; @Id private Long id; @Field(type = FieldType.Keyword) private String productSn; private Long brandId; @Field(type = FieldType.Keyword) private String brandName; private Long productCategoryId; @Field(type = FieldType.Keyword) private String productCategoryName; private String pic; @Field(analyzer = "ik_max_word",type = FieldType.Text) private String name; @Field(analyzer = "ik_max_word",type = FieldType.Text) private String subTitle; @Field(analyzer = "ik_max_word",type = FieldType.Text) private String keywords; private BigDecimal price; private Integer sale; private Integer newStatus; private Integer recommandStatus; private Integer stock; private Integer promotionType; private Integer sort; @Field(type =FieldType.Nested) private List<EsProductAttributeValue> attrValueList; }
这样就拥有了一些基本的Elasticsearch数据操作方法,同时定义了一个衍生查询方法;
/** * @description 商品ES操作类 */ public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> { /** * 搜索查询 * * @param name 商品名称 * @param subTitle 商品标题 * @param keywords 商品关键字 * @param page 分页信息 * @return */ Page<EsProduct> findByNameOrSubTitleOrKeywords(String name, String subTitle, String keywords, Pageable page); }
/** * @description 商品搜索管理Service */ public interface EsProductService { /** * 从数据库中导入所有商品到ES */ int importAll(); /** * 根据id删除商品 */ void delete(Long id); /** * 根据id创建商品 */ EsProduct create(Long id); /** * 批量删除商品 */ void delete(List<Long> ids); /** * 根据关键字搜索名称或者副标题 */ Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize); }
/** * @description 搜索商品管理Service实现类 */ @Service public class EsProductServiceImpl implements EsProductService { private static final Logger LOGGER = LoggerFactory.getLogger(EsProductServiceImpl.class); @Autowired private EsProductDao productDao; @Autowired private EsProductRepository productRepository; @Override public int importAll() { List<EsProduct> esProductList = productDao.getAllEsProductList(null); Iterable<EsProduct> esProductIterable = productRepository.saveAll(esProductList); Iterator<EsProduct> iterator = esProductIterable.iterator(); int result = 0; while (iterator.hasNext()) { result++; iterator.next(); } return result; } @Override public void delete(Long id) { productRepository.deleteById(id); } @Override public EsProduct create(Long id) { EsProduct result = null; List<EsProduct> esProductList = productDao.getAllEsProductList(id); if (esProductList.size() > 0) { EsProduct esProduct = esProductList.get(0); result = productRepository.save(esProduct); } return result; } @Override public void delete(List<Long> ids) { if (!CollectionUtils.isEmpty(ids)) { List<EsProduct> esProductList = new ArrayList<>(); for (Long id : ids) { EsProduct esProduct = new EsProduct(); esProduct.setId(id); esProductList.add(esProduct); } productRepository.deleteAll(esProductList); } } @Override public Page<EsProduct> search(String keyword, Integer pageNum, Integer pageSize) { Pageable pageable = PageRequest.of(pageNum, pageSize); return productRepository.findByNameOrSubTitleOrKeywords(keyword, keyword, keyword, pageable); } }
/** * @description 搜索商品管理Controller */ @Controller @Api(tags = "EsProductController") @Tag(name = "EsProductController", description = "搜索商品管理") @RequestMapping("/esProduct") public class EsProductController { @Autowired private EsProductService esProductService; @ApiOperation(value = "导入所有数据库中商品到ES") @RequestMapping(value = "/importAll", method = RequestMethod.POST) @ResponseBody public CommonResult<Integer> importAllList() { int count = esProductService.importAll(); return CommonResult.success(count); } @ApiOperation(value = "根据id删除商品") @RequestMapping(value = "/delete/{id}", method = RequestMethod.GET) @ResponseBody public CommonResult<Object> delete(@PathVariable Long id) { esProductService.delete(id); return CommonResult.success(null); } @ApiOperation(value = "根据id批量删除商品") @RequestMapping(value = "/delete/batch", method = RequestMethod.POST) @ResponseBody public CommonResult<Object> delete(@RequestParam("ids") List<Long> ids) { esProductService.delete(ids); return CommonResult.success(null); } @ApiOperation(value = "根据id创建商品") @RequestMapping(value = "/create/{id}", method = RequestMethod.POST) @ResponseBody public CommonResult<EsProduct> create(@PathVariable Long id) { EsProduct esProduct = esProductService.create(id); if (esProduct != null) { return CommonResult.success(esProduct); } else { return CommonResult.failed(); } } @ApiOperation(value = "简单搜索") @RequestMapping(value = "/search/simple", method = RequestMethod.GET) @ResponseBody public CommonResult<CommonPage<EsProduct>> search(@RequestParam(required = false) String keyword, @RequestParam(required = false, defaultValue = "0") Integer pageNum, @RequestParam(required = false, defaultValue = "5") Integer pageSize) { Page<EsProduct> esProductPage = esProductService.search(keyword, pageNum, pageSize); return CommonResult.success(CommonPage.restPage(esProductPage)); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。