全文搜索引擎elasticSearch
es尿崩式更新,三兩天就發佈一個新版本,到現在三兩年已經從1.0.0到7.x上百個版本,版本與springboot對應、語法都有不同,文檔還不好找,坑
第五部分記錄6.2.2版本的增刪改查操作、嵌套,網上現有的代碼基本都不能用
零 有價值的參考資料
一 安裝
- 安裝jdk
- elasticsearch官網下載 (默認9200端口,bin目錄下elasticsearch或elasticsearch.bat啓動)
- 可視化kibana官網下載 (默認5601端口,bin目錄下kibana啓動)
- 中文分詞插件IK下載 解壓到elasticsearch安裝目錄下plugins/ik,重啓es
- head插件,可視化配置、檢索、編輯數據
- logstash數據同步
二 功能用處
* 搜索引擎:只需要elasticsearch本體,webapp端引入依賴,通過相關api交互增刪改查;
* 聚合數據分析:需要kibana可視化、logstash日誌插件,分析數據;
三 結構
與數據庫區分,有自己的一套庫專門用於檢索,通過logstash或業務同步操作來同步數據。
四 整合sb
1 pom依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2 配置
# ELASTICSEARCH (ElasticsearchProperties)
# Elasticsearch cluster name.
spring.data.elasticsearch.cluster-name=elasticsearch_coldxiangyu
# Comma-separated list of cluster node addresses.
spring.data.elasticsearch.cluster-nodes= 127.0.0.1:9300
# Whether to enable Elasticsearch repositories.
spring.data.elasticsearch.repositories.enabled=true
3 建立接口
package com.coldxiangyu.elasticsearch.repository;
import com.coldxiangyu.elasticsearch.bean.QuestionBean;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* 接口關係:
* ElasticsearchRepository --> ElasticsearchCrudRepository --> PagingAndSortingRepository --> CrudRepository
*/
public interface QuestionRepository extends ElasticsearchRepository<QuestionBean, String> {
//Optional<BookBean> findById(String id);
}
ps:
- 所繼承的父類裏提供了findAll、findById等一些默認方法,可直接使用;例如
findAll——查詢所有數據,返回的是個迭代器
findById——根據id(主鍵)查詢
- 此接口中可聲明有一定格式的接口方法,可直接使用,會自動解析,例如
1 例子
findByAaBetweenOrderByBbDesc——查詢Aa字段介於兩個入參之間(包含邊界)的數據,按Bb倒序排序
findByNameStartingWith——查詢Name字段開頭爲入參的數據
Long countByLastname(String lastname)——計數
2 爲明確嵌套的屬性,可使用_分隔
findByAaBbCc 會識別爲AaBbCc,找不到再識別AaBb和Cc。可直接寫findByAa_BbCc,就會尋找Aa和BbCc
3 特殊條件
Page<User> findByLastname(String lastname, Pageable pageable);
Slice<User> findByLastname(String lastname, Pageable pageable);
List<User> findByLastname(String lastname, Sort sort);
List<User> findByLastname(String lastname, Pageable pageable);
第一個方法允許你傳遞一個org.springframework.data.domain.Pageable實例到查詢方法來動態的進行分頁。一個Page知道總數量和一共多少頁可用。它之所以知道這些是因爲底層框架觸發了一個技計數查詢來計算全部的數量。根據使用的數據存儲技術不同這可能消耗很大時間,可以使用Slice來替代它。Slice只知道是否存在下一個Slice可用,這將會非常適合查詢超大結果集。
排序操作也可以通過Pageable接口來處理。如果你僅僅需要排序那麼可以使用org.springframework.data.domain.Sort實例作爲方法參數。如你所見,查詢方法也可以僅僅返回一個List。這將約束查詢方法只查詢給定範圍的數據。
來源:https://www.jianshu.com/p/27e1d583aafb 1.4章
- 使用@query註解進行自定義查詢(自定義查詢方式一) 註解內爲elasticsearch json,格式如下
@Query("{\"bool\" : {\"must\" : {\"match\" : {\"name\" : \"?0\"}}}}")
public List<XxBean> findByNameLike(String name);
根據入參完全匹配name字段查詢
- 使用構造器自定義查詢(自定義查詢方式二,不在接口內寫)
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withFilter(regexpQuery("title", ".*data.*"))
.build();
List<Article> articles = elasticsearchTemplate.queryForList(searchQuery, Article.class);
查詢title字段包含data的數據
- 分頁可在參數中傳遞PageRequest,深度分頁需要scroll、scroll-scan
repository.findAll(new PageRequest(1, 20))
4 調用接口
package com.coldxiangyu.elasticsearch.service.impl;
import com.coldxiangyu.elasticsearch.bean.QuestionBean;
import com.coldxiangyu.elasticsearch.repository.QuestionRepository;
import com.coldxiangyu.elasticsearch.service.QuestionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service("questionService")
public class QuestionServiceImpl implements QuestionService {
@Autowired
@Qualifier("questionRepository")
private QuestionRepository questionRepository;
@Override
public Optional<QuestionBean> findById(String id) {
//CrudRepository中的方法
return questionRepository.findById(id);
}
@Override
public QuestionBean save(QuestionBean blog) {
return questionRepository.save(blog);
}
}
5 相關bean實體
package com.coldxiangyu.elasticsearch.bean;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
@Document(indexName = "qa_applicant_to_attachment", type = "_doc")
public class ApplicantAttachmentBean {
@Id
private String id;
private String applicantId;
private String attachmentId;
public ApplicantAttachmentBean(){}
public ApplicantAttachmentBean(String id, String applicantId, String attachmentId) {
this.id = id;
this.applicantId = applicantId;
this.attachmentId = attachmentId;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getApplicantId() {
return applicantId;
}
public void setApplicantId(String applicantId) {
this.applicantId = applicantId;
}
public String getAttachmentId() {
return attachmentId;
}
public void setAttachmentId(String attachmentId) {
this.attachmentId = attachmentId;
}
@Override
public String toString() {
return "AttachmentBean{" +
"id='" + id + '\'' +
", applicantId='" + applicantId + '\'' +
", attachmentId='" + attachmentId + '\'' +
'}';
}
}
五 注意點
* 深度分頁,頁數過多時佔用資源,使用scroll(有序)scroll-scan(無序);
* 提示不能以root用戶啓動
添加用戶 xxx爲你要添加的用戶名
useradd xxx
給xxx用戶設置密碼
passwd xxx
輸入密碼
再次輸入密碼
給xxx用戶權限,/ELK/elasticsearch-6.4.0是elasticsearch解壓根目錄
chown -R xxx /ELK/elasticsearch-6.4.0
切換用戶爲xxx
su xxx
再執行
./bin/elasticsearch
或者後臺執行
nohup ./bin/elasticsearch >elasticsearch.out &
即可成功
————————————————
版權聲明:本文爲CSDN博主「King-Long」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u011095110/article/details/82466299
* 公網訪問
修改配置文件config/elasticsearch.yml network.host: 0.0.0.0
* 與springboot版本
https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.requirements
* es映射類中可用@Field(type=FieldType.nested)嵌套對象,但嵌套對象不能直接操作,增刪改需要將整個對象查出,修改後再整個存回去(覆蓋回去)。至少2.x文檔是這麼說的。用put命令可以局部修改,但6.x的Script類參數大改,還沒研究出怎麼用,就先用了下述方法。
* es增刪改
/*
* es cud通信示例
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void saveQuestion2(QaQuestionES questionBean,String qaQuestionESId){
HashMap<String,Object> params = new HashMap<String,Object>();
params.put("questionDetail", JSON.toJSON(questionBean.getQuestionDetail()));
//6.x要用HashMap傳參,不能用json。嵌套對象則將value對象轉爲json,基本類型直接放。
//修改用prepareUpdate,增加用prepareIndex。三個參數分別爲映射類的索引、類型、主鍵。
elasticsearchTemplate.getClient().prepareUpdate(ESIndexName,ESTypeName,qaQuestionESId).setDoc(params).get();
}
//另一種通信方式
public void saveQuestion3(QaQuestionES.QuestionBean questionBean,String qaQuestionESId){
HashMap<String,Object> params = new HashMap<String,Object>();
UpdateRequest ur = new UpdateRequest();
ur.index(ESIndexName);
ur.type(ESTypeName);
ur.id(qaQuestionESId);
params.put("applicantTeam","四部");
ur.doc(params);
try {
elasticsearchTemplate.getClient().update(ur).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
* es查詢
public QaQuestionES findByQuestionId(String id){
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//查詢條件,嵌套對象下的條件則 父類屬性名.字段名
QueryBuilder queryBuilder = QueryBuilders.matchQuery("questionId", id);
boolQueryBuilder.must(queryBuilder);
SearchResponse response = elasticsearchTemplate.getClient().prepareSearch("qa_question").setQuery(boolQueryBuilder).get();
// 返回搜索結果
SearchHits hits = response.getHits();
for (SearchHit searchHit : hits) {
try {
QaQuestionES qaQuestionES = objectMapper.readValue(searchHit.getSourceAsString(), QaQuestionES.class);
return qaQuestionES;
} catch (Exception e) {
log.error("結果解析異常{}", e);
}
}
return null;
}
* 註解
- @Document註解實體類,indexName爲索引(對應庫),type爲類型(對應表)
- @id用於註解主鍵
- @Field註解嵌套的集合屬性時,type=FieldType.Nested
F 參考