1. elasticsearch
1.1 常用命令
Kibana 基本语法 API
method | url | desc |
---|---|---|
PUT | localhost:9200/索引名称/类型名称/文档id | 创建文档(指定文档id) |
POST | localhost:9200/索引名称/类型名称 | 创建文档(随机id) |
POST | localhost:9200/索引名称/_update/文档id | 修改文档 |
DELETE | localhost:9200/索引名称/类型名称/文档id | 删除文档 by id |
GET | localhost:9200/索引名称/类型名称/文档id | 查询文档 by id |
POST | localhost:9200/索引名称/_search | 查询所有文档 |
新建
#创建空库
PUT /test2
{
}
#创建索引 及 规定字段类型
PUT /test3
{
"mappings": {
"properties": {
"name":{
"type": "text"
},
"age":{
"type": "integer"
},
"birth":{
"type": "date"
}
}
}
}
#创建数据
PUT /wanghl/_doc/2
{
"name":"花木兰",
"age":67,
"tags":["战士","上单","女"]
}
删除
#删除索引
DELETE test2
#删除文档
DELETE test1/_doc/3
修改
#修改文档
POST /test1/_update/4
{
"doc":{
"name":"红桃A"
}
}
查询
_source 字段过滤 不写默认 select *
#获取索引库
GET test3
#获取文档by文档id
GET wanghl/_doc/2
#根据属性查询 简写
GET wanghl/_search?q=name:李
#构建式查询
#_source 字段过滤 不写默认 select *
# from size 分页
GET /wanghl/_search
{
"query": {
"match": {
"tags": "男"
}
},
"_source": ["name","tags"],
"from":0,
"size":1
}
#多条件查询 must 相当于 and should 相当于 or
GET wanghl/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"tags": "男 下路"
}
}
],
"must_not": [
{
"match": {
"age": "3"
}
}
]
}
}
}
# 查询过滤 + 高亮显示
GET wanghl/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"tags": "男"
}
}
] ,
"filter": [
{
"range": {
"age": {
"gte": 10,
"lte": 200
}
}
}
]
}
},
"highlight": {
"pre_tags": "<font>",
"post_tags": "</font>",
"fields": {
"tags": {}
}
}
}
其中gt代表大于,gte代表大于等于,lt小于,lte小于等于
GET website/_search
{
"query": {
"range": {
"post_date": {
"gte": "now-1d/d", // 当前时间的上一天, 四舍五入到最近的一天
"lt": "now/d" // 当前时间, 四舍五入到最近的一天
}
}
}
}
Elasticsearch中时间可以表示为now
, 也就是系统当前时间, 也可以是以||
结尾的日期字符串表示.
在日期之后, 可以选择一个或多个数学表达式:
+1h
—— 加1小时;-1d
—— 减1天;/d
—— 四舍五入到最近的一天
下面是Elasticsearch支持数学表达式的时间单位:
表达式 | 含义 | 表达式 | 含义 |
---|---|---|---|
y |
年 | M |
月 |
w |
星期 | d |
天 |
h |
小时 | H |
小时 |
m |
分钟 | s |
秒 |
说明: 假设系统当前时间now = 2018-10-01 12:00:00
:
now+1h
: now的毫秒值 + 1小时, 结果是:2018-10-01 13:00:00
.now-1h
: now的毫秒值 - 1小时, 结果是:2018-10-01 11:00:00
.now-1h/d
: now的毫秒值 - 1小时, 然后四舍五入到最近的一天的起始, 结果是:2018-10-01 00:00:00
.2018.10.01||+1M/d
:2018-10-01
的毫秒值 + 1月, 再四舍五入到最近一天的起始, 结果是:2018-11-01 00:00:00
.
关于时间的四舍五入
对日期中的日、月、小时等 进行四舍五入时, 取决于范围的结尾是包含(include)还是排除(exclude).
向上舍入: 移动到舍入范围的最后一毫秒;
向下舍入: 一定到舍入范围的第一毫秒.
举例说明:
① "gt": "2018-12-18||/M" —— 大于日期, 需要向上舍入, 结果是2018-12-31T23:59:59.999
, 也就是不包含整个12月.
② "gte": "2018-12-18||/M" —— 大于或等于日期, 需要向下舍入, 结果是 2018-12-01
, 也就是包含整个12月.
③ "lt": "2018-12-18||/M" —— 小于日期, 需要向上舍入, 结果是2018-12-01
, 也就是不包含整个12月.
④ "lte": "2018-12-18||/M" —— 小于或等于日期, 需要向下舍入, 结果是2018-12-31T23:59:59.999
, 也就是包含整个12月.
日期格式化范围查询(format)
格式化日期查询时, 将默认使用日期field中指定的格式进行解析, 当然也可以通过format参数来覆盖默认配置.
示例:
GET website/_search
{
"query": {
"range": {
"post_date": {
"gte": "2/1/2018",
"lte": "2019",
"format": "dd/MM/yyyy||yyyy"
}
}
}
}
注意: 如果日期中缺失了部分年、月、日, 缺失的部分将被填充为unix系统的初始值, 也就是1970年1月1日.
比如, 将dd
指定为format, 像"gte": 10
将转换为1970-01-10T00:00:00.000Z
.
时区范围查询(time_zone)
如果日期field的格式允许, 也可以通过在日期值本身中指定时区, 从而将日期从另一个时区的时间转换为UTC时间, 或者为其指定特定的time_zone
参数.
GET website/_search
{
"query": {
"range": {
"post_date": {
"gte": "2018-01-01 00:00:00",
"lte": "now",
"format": "yyyy-MM-dd hh:mm:ss",
"time_zone": "+1:00"
}
}
}
}
ES中的日期类型必须按照UTC时间格式存储, 所以, 上述的2018-01-01 00:00:00
将被转换为2017-12-31T23:00:00 UTC
.
另外需要注意的是, now
是不受time_zone
影响的.
合并查询语句
复合(Compound) 语句 主要用于 合并其它查询语句。 比如,一个 bool
语句 允许在你需要的时候组合其它语句,无论是 must
匹配、 must_not
匹配还是 should
匹配,同时它可以包含不评分的过滤器(filters):
{
"bool": {
"must": { "match": { "tweet": "elasticsearch" }},
"must_not": { "match": { "name": "mary" }},
"should": { "match": { "tweet": "full text" }},
"filter": { "range": { "age" : { "gt" : 30 }} }
}
}
2. Springboot 整合elasticsearch
主要介绍了SpringBoot整合Spring Data Elasticsearch的过程详解
2.1 ElasticsearchTemplate
Spring Data Elasticsearch提供了ElasticsearchTemplate工具类,实现了POJO与elasticsearch文档之间的映射elasticsearch本质也是存储数据,它不支持事物,但是它的速度远比数据库快得多,可以这样来对比lasticsearch和数据库的关系。
- 索引(indices)--------数据库(databases)
- 类型(type)------------数据表(table)
- 文档(Document)---------------- 行(row)
- 字段(Field)-------------------列(Columns )
2.1.1 整合过程
1,在SprinBoot工程中引入jar包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>
2,配置文件
spring.data.elasticsearch.cluster-name=elasticsearch //名字必须和elasticsearch.yml里面的cluster.name相同spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300 #开启 Elasticsearch 仓库(默认值:true)spring.data.elasticsearch.repositories.enabled=true
配置文件助记
# ES#开启 Elasticsearch 仓库(默认值:true)spring.data.elasticsearch.repositories.enabled=true#默认 9300 是 Java 客户端的端口。9200 是支持 Restful HTTP 的接口spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300#spring.data.elasticsearch.cluster-name Elasticsearch 集群名(默认值: elasticsearch)#spring.data.elasticsearch.cluster-nodes 集群节点地址列表,用逗号分隔。如果没有指定,就启动一个客户端节点#spring.data.elasticsearch.propertie 用来配置客户端的额外属性#存储索引的位置spring.data.elasticsearch.properties.path.home=/data/project/target/elastic#连接超时的时间spring.data.elasticsearch.properties.transport.tcp.connect_timeout=120s
server.port=8080server.servlet.context-path=/ems#https://blog.csdn.net/haohaifeng002/article/details/102887921spring.elasticsearch.rest.uris=http://localhost:9200spring.elasticsearch.rest.username=elasticspring.elasticsearch.rest.password=123456
配置只有一句,但需要强调下,我们的elasticsearch服务端是当前的最新版本7.4.1。Elasticsearch从7开始不推荐使用TransportClient客户端访问,8会彻底删除该客户端API的支持,推荐用High Level REST Client(见参考1),所以此处配置使用spring.elasticsearch.rest.uris,默认值为http://localhost:9200,可以是多个uri。之前如spring.data.elasticsearch.cluster-name=my-application spring.data.elasticsearch.cluster-nodes=127.0.0.1:9300的TransportClient配置方式已被标记为过时。
3,创建实体,并对类和属性进行标注
@Document(indexName = "item",type = "docs", shards = 1, replicas = 0)//标记为文档类型,indexName:对应索引库名称 type:对应在索引库中的类型,shards:分片数量,默认5,replicas:副本数量,默认1public class Item { @Id //主键 private Long id; @Field (type = FieldType.Text, analyzer = "ik_max_word" ) //标记为成员变量 FieldType,可以是text、long、short、date、integer等 //text:存储数据时候,会自动分词,并生成索引 keyword:存储数据时候,不会分词建立索引 analyzer:分词器名称 private String title; //标题 @Field (type = FieldType.Keyword) private String category; // 分类 @Field (type = FieldType.Keyword) private String brand; // 品牌 @Field (type = FieldType.Double) private Double price; // 价格 @Field (index = false , type = FieldType.Keyword) //index:是否索引 private String images; // 图片地址
4.引入模板ElasticsearchTemplate
@Autowiredprivate ElasticsearchTemplate elasticsearchTemplate;
5.创建一个索引
//添加索引@Testpublic void addIndex() { elasticsearchTemplate.createIndex(Item.class );}
6.删除索引
//删除索引@Testpublic void delete(){ elasticsearchTemplate.deleteIndex( "item" );}
7.新增对象
继承Repository提供的一些子接口,就能具备各种基本的CRUD功能,这里继承ElasticsearchCrudRepository
首先定义一个对象的接口
public interface ItemRepository extends ElasticsearchCrudRepository<Item,Long> {}
然后注入ItemRepository
@Autowiredprivate ItemRepository itemRepository;
新增对象
//新增一个对象 @Test public void insert(){ Item item = new Item(2L, "坚果R1" , "手机" , "锤子" , 2500.00 , "http://image.baidu.com/13123.jpg" ); //Order order = new Order(20180020,"菜单"); itemRepository.save(item); }
批量新增
//批量新增 @Test public void insertList(){ List<Item> list = new LinkedList<>(); list.add(new Item(9L,"华为p20","手机","华为",3500.00,"http://image.baidu.com/13123.jpg")); list.add(new Item(10L,"华为p30","手机","华为",5450.00,"http://image.baidu.com/13123.jpg")); list.add(new Item(11L,"华为p30 pro","手机","华为",6980.00,"http://image.baidu.com/13123.jpg")); itemRepository.saveAll(list); }
8.查询
//根据字段查询所有 @Test public void queryAll(){ //升序,相应降序为dscending Iterable<Item> items = this.itemRepository.findAll(Sort.by("price").ascending()); for (Item item : items){ System.out.println(item); } }
9.自定义查询方法
Spring Data 的另一个强大功能,是根据方法名称自动实现功能,你的方法名叫做:findByTitle,那么它就知道你是根据title查询,然后自动帮你完成,无需写实现类。当然,方法名称要符合一定的约定:
使用自定义方法需要在接口里面申明方法
public interface ItemRepository extends ElasticsearchCrudRepository<Item,Long> { Item findByTitle(String title); List<Item> findByPriceBetween(double price1, double price2); List<Item> findByTitleLike(String title);}
根据手机名查找手机
//自定义方法,根据Title查询 @Test public void findByTitle(){ Item item = this.itemRepository.findByTitle("坚果pro"); System.out.println(item); }
区间查询
//根据区间查询 @Test public void queryByPriceBetween(){ List<Item> list = this.itemRepository.findByPriceBetween(2000.00, 3500.00); for (Item item : list) { System.out.println("item = " + item); } }
模糊查询
//模糊查询 @Test public void queryLikeTitle(){ List<Item> list = this.itemRepository.findByTitleLike("R2"); for (Item item : list){ System.out.println(item); } }
10.自定义查询
//自定义查询,查询数目等 @Test public void matchQuery(){ // 构建查询条件 NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); // 添加基本分词查询 queryBuilder.withQuery(QueryBuilders.matchQuery("title","坚果")); //获取结果 Page<Item> items = (Page<Item>) this.itemRepository.findAll(); //条数 long total = items.getTotalElements(); System.out.println("total = "+total); for (Item item : items){ System.out.println(item); } }关键的是NativeSearchQueryBuilder这个类
分页查询
//分页查询 @Test public void queryByPage(){ NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("category","手机")); int page = 0; int size = 2; nativeSearchQueryBuilder.withPageable(PageRequest.of(page,size)); Page<Item> items = (Page<Item>) this.itemRepository.findAll(); long total = items.getTotalElements(); int totalPage = items.getTotalPages(); int nowPage = items.getNumber(); int pageSize = items.getSize(); System.out.println("总条数 = "+total); System.out.println("总页数 = "+totalPage); System.out.println("当前页 = "+nowPage); System.out.println("每页大小 = "+pageSize); for (Item item : items){ System.out.println(item); } }
有些在复杂的可以使用es查询语句
我们可以使用@Query注解进行查询,这样要求我们需要自己写ES的查询语句
public interface BookRepository extends ElasticsearchRepository<Book, String> { @Query("{"bool" : {"must" : {"field" : {"name" : "?0"}}}}") Page<Book> findByName(String name,Pageable pageable);}
//默认的注释 //@Query("{"bool" : {"must" : {"field" : {"content" : "?"}}}}") Page<DocBean> findByContent(String content, Pageable pageable); @Query("{"bool" : {"must" : {"field" : {"firstCode.keyword" : "?"}}}}") Page<DocBean> findByFirstCode(String firstCode, Pageable pageable); @Query("{"bool" : {"must" : {"field" : {"secordCode.keyword" : "?"}}}}") Page<DocBean> findBySecordCode(String secordCode, Pageable pageable);————————————————版权声明:本文为CSDN博主「程裕强」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/chengyuqiang/article/details/102938266
方法和es查询转换:
Keyword | Sample | Elasticsearch Query String |
---|---|---|
And |
findByNameAndPrice |
{"bool" : {"must" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Or |
findByNameOrPrice |
{"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"price" : "?"}} ]}} |
Is |
findByName |
{"bool" : {"must" : {"field" : {"name" : "?"}}}} |
Not |
findByNameNot |
{"bool" : {"must_not" : {"field" : {"name" : "?"}}}} |
Between |
findByPriceBetween |
{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
LessThanEqual |
findByPriceLessThan |
{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
GreaterThanEqual |
findByPriceGreaterThan |
{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Before |
findByPriceBefore |
{"bool" : {"must" : {"range" : {"price" : {"from" : null,"to" : ?,"include_lower" : true,"include_upper" : true}}}}} |
After |
findByPriceAfter |
{"bool" : {"must" : {"range" : {"price" : {"from" : ?,"to" : null,"include_lower" : true,"include_upper" : true}}}}} |
Like |
findByNameLike |
{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
StartingWith |
findByNameStartingWith |
{"bool" : {"must" : {"field" : {"name" : {"query" : "?*","analyze_wildcard" : true}}}}} |
EndingWith |
findByNameEndingWith |
{"bool" : {"must" : {"field" : {"name" : {"query" : "*?","analyze_wildcard" : true}}}}} |
Contains/Containing |
findByNameContaining |
{"bool" : {"must" : {"field" : {"name" : {"query" : "**?**","analyze_wildcard" : true}}}}} |
In |
findByNameIn(Collection<String>names) |
{"bool" : {"must" : {"bool" : {"should" : [ {"field" : {"name" : "?"}}, {"field" : {"name" : "?"}} ]}}}} |
NotIn |
findByNameNotIn(Collection<String>names) |
{"bool" : {"must_not" : {"bool" : {"should" : {"field" : {"name" : "?"}}}}}} |
Near |
findByStoreNear |
Not Supported Yet ! |
True |
findByAvailableTrue |
{"bool" : {"must" : {"field" : {"available" : true}}}} |
False |
findByAvailableFalse |
{"bool" : {"must" : {"field" : {"available" : false}}}} |
OrderBy |
findByAvailableTrueOrderByNameDesc |
{"sort" : [{ "name" : {"order" : "desc"} }],"bool" : {"must" : {"field" : {"available" : true}}}} |