156人参与 • 2024-08-02 • Erlang
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));
}
}
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论