文章目錄
- SpringBoot集成
- 添加POM依賴
- 組態檔
- 創建映射物件
- 創建Repository介面
- 常見操作
- 索引操作
- 新增資料
- 洗掉資料
- 更新資料
- 更新某幾個欄位
- 查詢
- 普通查詢
- 分頁查詢
- 高亮查詢
- 權重查詢
- 聚合查詢
- 監控管理
- 問題總結
- 索引映射創建
- 排序查詢報錯
Elasticsearch部署請參考:【 https://laker.blog.csdn.net/article/details/120977484】
Elasticsearch官網檔案:https://www.elastic.co/guide/en/elasticsearch/client/index.html
SpringBoot集成
我使用的版本為
SpringBoot2.3.7RELEASE,對應的ES版本為7.6.2.
添加POM依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
SpringBoot版本以及對應Elasticsearch版本如下圖:
以
SpringBoot2.3.7RELEASE版本為例子,

Spring Data Elasticsearch從 4.0 版本起不推薦使用 ElasticsearchTemplate,請改用 ElasticsearchRestTemplate,
下表顯示了Spring Data發布系列所使用的Elasticsearch版本和其中包含的Spring Data Elasticsearch版本,以及針對特定Spring Data發布系列的Spring Boot版本:
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot |
|---|---|---|---|---|
| 2021.1 (Q) | 4.3.x | 7.15.2 | 5.3.x | 2.5 .x |
| 2021.0 (Pascal) | 4.2.x | 7.12.0 | 5.3.x | 2.5.x |
| 2020.0 (Ockham) | 4.1.x | 7.9.3 | 5.3.2 | 2.4.x |
| Neumann | 4.0.x | 7.6.2 | 5.2.12 | 2.3.x |
| Moore | 3.2.x | 6.8.12 | 5.2.12 | 2.2.x |
| Lovelace | 3.1.x | 6.2.2 | 5.1.19 | 2.1.x |
| Kay | 3.0.x | 5.5.0 | 5.0.13 | 2.0.x |
| Ingalls | 2.1.x | 2.4.0 | 4.3.25 | 1.5.x |
-
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.rest
-
https://docs.spring.io/spring-data/elasticsearch/docs/4.0.6.RELEASE/reference/html/#new-features
-
https://github.com/spring-projects/spring-data-elasticsearch
組態檔
spring:
elasticsearch:
rest:
# ES的連接地址,多個地址用逗號分隔
uris: http://127.0.0.1:9200
# 讀取超時時間
read-timeout: 30s
# 連接超時時間
connection-timeout: 1s
# 用戶名
username:
# 密碼
password:
注: 9300 是 Java 客戶端的埠,9200 是支持 Restful HTTP 的介面,
創建映射物件
/**
* 注解:@Document用來宣告Java物件與ElasticSearch索引的關系
* indexName 索引名稱
* shards 主磁區數量,默認1
* replicas 副本磁區數量,默認1
* createIndex 索引不存在時,是否自動創建索引,默認true
*/
@Data
@Document(indexName = "goods_index", shards = 1, replicas = 0, createIndex = true)
public class Goods {
/**
* id
*/
@Id
private Long id;
/**
* 商品編號,不可使用分詞器查詢,精準匹配 FieldType.Keyword
*/
@Field(type = FieldType.Keyword)
private String goodsCode;
/**
* 商品名稱,可以使用分詞器查詢,模糊匹配
*/
@Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
private String goodsName;
/**
* 商品發布時間
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@Field(type = FieldType.Date, format = DateFormat.basic_date_time)
private Date createDate;
/**
* 排名 默認都是100
*/
@Field(type = FieldType.Integer)
private Integer hotScore = 100;
/**
* 內嵌欄位
*/
@Field(type = FieldType.Nested)
private List<GoodsAttr> attrs;
}
映射詳情 :https://docs.spring.io/spring-data/elasticsearch/docs/4.0.6.RELEASE/reference/html/#elasticsearch.mapping.meta-model
- @Id 作用在成員變數,標記一個欄位作為id主鍵
- @Field 作用在成員變數,標記為檔案的欄位,并指定欄位映射屬性:
- type:欄位型別,是列舉:FieldType,可以是text、long、short、date、integer、object等
- text:存盤資料時候,會自動分詞,并生成索引
- keyword:存盤資料時候,不會分詞建立索引
- Numerical:數值型別,分兩類
- 基本資料型別:long、interger、short、byte、double、float、half_float
- 浮點數的高精度型別:scaled_float
- 需要指定一個精度因子,比如10或100,elasticsearch會把真實值乘以這個因子后存盤,取出時再還原
- Date:日期型別
- elasticsearch可以對日期格式化為字串存盤,但是建議我們存盤為毫秒值,存盤為long,節省空間,
- index:是否索引,是否設定分詞,布爾型別,默認是true
- store:是否存盤,布爾型別,默認是false
- analyzer:分詞器名稱,存盤時使用的分詞器,這里的ik_max_word即使用ik分詞器
- searchAnalyze:搜索時使用的分詞器
- type:欄位型別,是列舉:FieldType,可以是text、long、short、date、integer、object等
創建Repository介面
@Repository
public interface GoodsRepository extends ElasticsearchRepository<Goods, Long> {
}
常見操作
我們在操作索引和資料時,需要參考下面的類
@Autowired 用于高級查詢
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Autowired 用于基礎的CRUD
private GoodsRepository goodsRepository;
@Autowired
private RestHighLevelClient restHighLevelClient;
@Bean
RestHighLevelClient client() {
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration)
.rest();
}
索引操作
# 判斷索引是否存在
elasticsearchRestTemplate.indexOps(Goods.class).exists();
elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexNames)).exists();
# 創建索引
elasticsearchRestTemplate.indexOps(Goods.class).create();
# 洗掉索引
elasticsearchRestTemplate.indexOps(IndexCoordinates.of(indexName)).delete();
if (!esService.indexExists()) {
esService.indexCreate();
}
新增資料
Goods goods = new Goods();
goods.setId((long) i);
goods.setGoodsCode("中國人" + i);
goods.setCreateDate(new Date());
goods.setHotScore(10);
goods.setGoodsName("我是中國人" + i);
# 新增
goodsRepository.save(goods);
# 批量新增
goodsRepository.saveAll(goodsList);

洗掉資料
# 根據ID,洗掉資料
goodsRepository.deleteById(id);
# 根據物件洗掉資料,主鍵ID不能為空
goodsRepository.delete(bean);
# 根據物件集合,批量洗掉
goodsRepository.deleteAll(beanList);
# 洗掉所有
goodsRepository.deleteAll();
更新資料
Goods goods = new Goods();
goods.setId(id); // ID不能為空
goods.setGoodsCode("中國人");
goodsRepository.save(goods);// 根據主鍵更新 ID不能為空
更新某幾個欄位
查詢
ElasticsearchRestTemplate的基本api
- SearchQuery 總的查詢
- BoolQueryBuilder bool查詢,可在后面加上must,mustNot,should等等
- MatchQueryBuilder 匹配查詢
- TermQueryBuilder 倒排索引查詢
- HighlightBuilder 高亮查詢,用于設定要高亮的field
查詢結果
SearchHit
包含以下資訊:
-
Id
-
Score
-
Sort Values
-
Highlight fields
-
The retrieved entity of type
SearchHits
包含以下資訊:
- Number of total hits
- Total hits relation
- Maximum score
- A list of
SearchHit<T>objects - Returned aggregations
SearchPage
定義一個Spring Data Page 包含一個 SearchHits<T> 元素,可以使用存盤庫方法進行分頁訪問
SearchScrollHits
由ElasticsearchRestTemplate中的底層滾動API函式回傳,它用Elasticsearch滾動id充實了SearchHits,
SearchHitsIterator
由SearchOperations介面的流函式回傳的迭代器,
QueryBuilders提供了大量的靜態方法,用于生成各種不同型別的查詢:
- matchQuery:詞條匹配,先分詞然后在呼叫termQuery進行匹配
- TermQuery:詞條匹配,不分詞
- wildcardQuery:通配符匹配
- fuzzyQuery:模糊匹配
- rangeQuery:范圍匹配
- booleanQuery:布爾查詢,組合查詢
// 構建查詢條件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本分詞查詢
queryBuilder.withQuery(QueryBuilders.matchQuery(“title”, “小米手機”));
BooleanQuery(組合查詢)

注意點:
BooleanClause用于表示布爾查詢子句關系的類,包括:BooleanClause.Occur.MUST,BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.SHOULD,必須包含,不能包含,可以包含三種.有以下6種組合:
1.MUST和MUST:交集,
2.MUST和MUST_NOT:表示查詢結果中不能包含MUST_NOT所對應得查詢子句的檢索結果,
3.SHOULD與MUST_NOT:連用時,功能同MUST和MUST_NOT,
4.SHOULD與MUST連用時,結果為MUST子句的檢索結果,但是SHOULD可影響排序,
5.SHOULD與SHOULD:并集,
6.MUST_NOT和MUST_NOT:無意義,檢索無結果,
public void testBooleanQuery(){
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
builder.withQuery(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("title","手機"))
.must(QueryBuilders.termQuery("brand","小米"))
);
Page<Item> list = this.itemRepository.search(builder.build());
排序
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
// 添加基本分詞查詢
queryBuilder.withQuery...
// 排序
queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
普通查詢
可以使用goodsRepository操作
@Repository
public interface GoodsRepository extends ElasticsearchRepository<Goods, Long> {
long countByGoodsCode(String goodsCode);
long deleteByGoodsCode(String goodsCode);
List<Goods> removeByGoodsCode(String goodsCode);
List<Goods> findByGoodsCode(String goodsCode);
Page<Goods> findByGoodsCode(String goodsCode, Pageable pageable);
Slice<Goods> findByGoodsCode(String goodsCode, Pageable pageable);
List<Goods> findByGoodsCode(String goodsCode, Sort sort);
List<Goods> findFirst10ByGoodsCode(String goodsCode, Pageable pageable);
@Query("{\"bool\": {\"must\": [{\"match\": {\"tags\": \"?0\"}}]}}")
Page<Goods> findFirst10ByGoodsCode(String tag, Pageable pageable);
Page<Article> findByAuthorsName(String name, Pageable pageable);
@Query("{\"bool\": {\"must\": [{\"match\": {\"authors.name\": \"?0\"}}]}}")
Page<Article> findByAuthorsNameUsingCustomQuery(String name, Pageable pageable);
@Query("{\"bool\": {\"must\": {\"match_all\": {}}, \"filter\": {\"term\": {\"tags\": \"?0\" }}}}")
Page<Article> findByFilteredTagQuery(String tag, Pageable pageable);
@Query("{\"bool\": {\"must\": {\"match\": {\"authors.name\": \"?0\"}}, \"filter\": {\"term\": {\"tags\": \"?1\" }}}}")
Page<Article> findByAuthorsNameAndFilteredTagQuery(String name, String tag, Pageable pageable);
}
API 接受
Sort和Pageable,如果您不想應用任何排序或分頁,請使用Sort.unsorted()和Pageable.unpaged(),不要傳null,Sort sort = Sort.by(“firstname”).ascending()
? .and(Sort.by(“lastname”).descending());
與Elasticsearch 查詢字串映射如下:https://docs.spring.io/spring-data/elasticsearch/docs/4.0.6.RELEASE/reference/html/#elasticsearch.query-methods.criterions
分頁查詢
Page<User> users = repository.findAll(PageRequest.of(1, 20));
MatchQueryBuilder builder = QueryBuilders.matchQuery(field, value);
SearchQuery searchQuery = new NativeSearchQuery(builder).setPageable(PageRequest.of(0, 100));
AggregatedPage<EmployeeBean> page = restTemplate.queryForPage(searchQuery, EmployeeBean.class);
long totalElements = page.getTotalElements(); // 總記錄數
int totalPages = page.getTotalPages(); // 總頁數
int pageNumber = page.getPageable().getPageNumber(); // 當前頁號
List<EmployeeBean> beanList = page.toList(); // 當前頁資料集
Set<EmployeeBean> beanSet = page.toSet(); // 當前頁資料集
高亮查詢
權重查詢
聚合查詢
監控管理
ElasticHQ可以作為Docker容器使用,執行以下命令以使用ElasticHQ啟動容器:
$ docker run -d --name elastichq -p 5000:5000 elastichq/elasticsearch-hq
問題總結
索引映射創建
方式一 在物體類上加**@Document**,而在這個類中有一個createIndex屬性,默認為true,意思是在啟動應用時es中還沒創建該索引,則進行初始化,
下面是默認創建的索引和映射,很明顯里面的映射創建是不對,不建議使用這種方式,
es服務端版本為7.3.0,不知道是不是不完全匹配的原因,試了7.6.2版本也不對哈哈哈,
{
"state": "open",
"settings": {
"index": {
"refresh_interval": "1s",
"number_of_shards": "1",
"provided_name": "goods_index",
"creation_date": "1640695057235",
"store": {
"type": "fs"
},
"number_of_replicas": "0",
"uuid": "La3XlrTTTu6-SoNtsuPl1g",
"version": {
"created": "7030099"
}
}
},
"mappings": {
"_doc": {
"properties": {
"hotScore": {
"type": "long"
},
"_class": {
"type": "text",
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
},
"goodsCode": {
"type": "text",
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
},
"id": {
"type": "long"
},
"goodsName": {
"type": "text",
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
},
"createDate": {
"type": "text",
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
}
}
}
}
方式二 使用postman、elasticsearch-head等提交put請求創建索引和映射,
這個就不用講了哈,最原始的了,
方式三 設定**@Document**,的createIndex屬性為false,然后使用代碼初始化索引和映射,
public boolean indexAndMappingCreate() {
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(Goods.class);
boolean exists = indexOperations.exists();
if (exists) {
return true;
}
boolean index = indexOperations.create();
Document mapping = indexOperations.createMapping(Goods.class);
boolean putMapping = indexOperations.putMapping(mapping);
if (index && putMapping) {
return true;
} else {
return false;
}
}
不支持fielddata = true
@Field(type = FieldType.Integer, fielddata = true)
private Integer hotScore = 100;
結果如下:
{
"state": "open",
"settings": {
"index": {
"refresh_interval": "1s",
"number_of_shards": "1",
"provided_name": "goods_index",
"creation_date": "1640697770606",
"store": {
"type": "fs"
},
"number_of_replicas": "0",
"uuid": "_N7I0GAJRsitjTbs9XnOcQ",
"version": {
"created": "7030099"
}
}
},
"mappings": {
"_doc": {
"properties": {
"hotScore": {
"type": "integer"
},
"goodsCode": {
"type": "keyword"
},
"goodsName": {
"search_analyzer": "ik_smart",
"analyzer": "ik_max_word",
"type": "text"
},
"attrs": {
"type": "nested"
},
"createDate": {
"format": "basic_date_time",
"type": "date"
}
}
}
},
方式四 使用RestHighLevelClient發起請求,類似于postman發起put請求,
@Autowired
@Qualifier("elasticsearchClient")
protected RestHighLevelClient client;
方式五
排序查詢報錯
排序欄位【goodsCode】需要設定fielddata=true. 需要對 string型別的欄位,單獨設定加載到記憶體中,才能排序,
Fielddata is disabled on text fields by default. Set fielddata=true on [goodsCode] in order to load fielddata in memory by uninverting the inverted index
查詢時錯誤如下:
Caused by: ElasticsearchException[Elasticsearch exception [type=illegal_argument_exception, reason=Fielddata is disabled on text fields by default. Set fielddata=true on [goodsCode] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.]]
at org.elasticsearch.ElasticsearchException.innerFromXContent(ElasticsearchException.java:496)
at org.elasticsearch.ElasticsearchException.fromXContent(ElasticsearchException.java:407)
at org.elasticsearch.ElasticsearchException.innerFromXContent(ElasticsearchException.java:437)
... 46 more
參考:
-
https://www.baeldung.com/spring-data-elasticsearch-queries
-
https://blog.csdn.net/weixin_43814195/article/details/85281287
-
https://www.cnblogs.com/huanshilang/p/14382279.html
-
https://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-elasticsearch
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/398537.html
標籤:其他
