一、spring cloud 引入spring-boot-starter-data-elasticsearch
1. spring cloud集成了elasticsearch,但是我们部署的elasticsearch版本要与引入的elasticsearch的jar版本一直
elasticsearch的版本引用之前文章中的elk搭建的版本
{
"cluster_name" : "elasticsearch",
"version" : {
"number" : "6.8.3",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "0c48c0e",
"build_date" : "2019-08-29T19:05:24.312154Z",
"build_snapshot" : false,
"lucene_version" : "7.7.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
引入pom
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2. 配置文件配置
spring:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 192.168.12.122:9300
repositories:
enabled: true
//切记这里是9300 不是9200. 9300是客户端连接的服务
3. 与之前hibernate一样,elasticsearch也有mapping。给实体类添加注解。
mapping是类似于数据库中的表结构定义,
1) 对象添加@Document注解,可以设置indexName、type、useServerConfiguration、shards、replicas、refreshInterval、indexStoreType、createIndex
indexName,定义当前对象索引,该对象就是一个文档(数据库)
type,文档逻辑分类,(数据库表)
2) 对象属性添加注解,@Field(type = FieldType.Keyword)
//text,当字段被全文搜索,设置后内容会被分析成一个一个词项,不用于排序
//keyword,适用于索引结构化字段,设置后可以排序、精确过滤、聚合。只能精确搜索
字符串类型 text,keyword
//数值类型,尽可能选择合适的,类型字段长度越短,索引和搜索效率越高
整数类型 integer,long, short, byte
浮点类型 double,float,half_float,scaled_float
逻辑类型 boolean
日期类型 date
范围类型 range
二进制类型 binary
数组类型 array
对象类型 object
嵌套类型 nested
地理坐标类型 geo_point
地理地图 geo_shape
IP类型 ip
范围类型 completion
令牌计数类型 token_count
附件类型 attachment
3) analyer,指定分词器,可以自定义按什么分词,例如:analyzer = "whitespace"按空格分词
standard分词器对一句中文进行分词,会分成一个字一个字。
第三方analyer插件,中文分词ik分词器,比如:ik、pinyin等。例如: analyzer = "ik_max_word",会把
你好吗?我有一句话要对你说呀。分成,你好,好吗,我,有,一句话,一句,一,句话,句,话,要对,你,说呀
分词之后检索更加快捷。
实体类:
@Document(indexName = "release", type = "inter_info", shards = 1, replicas = 0)
public class ReleaseDataBean implements Serializable {
private static final long serialVersionUID = 4454026607520652287L;
@Field(type = FieldType.Keyword)
private String id;
// 数据包的表名
private String dataSetTableName;
// 发布接口的名称
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String name;
// url类型
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String urlType;
// 请求类型
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String requestType;
// 操作人
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String operator;
// 发布时间
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String releaseDate;
// 数据包名称
private String dataSetName;
// 发布url
private String url;
// token验证
private String token;
4. 编写dao层,存取对象于elasticsearch
public interface ReleaseElasticRepository extends ElasticsearchRepository<ReleaseDataBean, Long> {
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \"?\"}}}}")
Page<ReleaseDataBean> findByName(String name, Pageable pageable);
}
参考:https://blog.youkuaiyun.com/weixin_40790313/article/details/84529265
5. service
@Autowired
private ReleaseElasticRepository releaseElasticRepository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Override
public void saveElasticRelease(ReleaseDataBean releaseDataBean) {
createIndex();
releaseElasticRepository.save(releaseDataBean);
}
private void createIndex() {
if(!elasticsearchTemplate.indexExists(ReleaseDataBean.class)) {
elasticsearchTemplate.createIndex(ReleaseDataBean.class);
}
}
番外:容易出错的点
1> 客户端连接端口是9300, 应用的端口是9200
2> 我们使用elk的docker打镜像,必须将9300端口发布出来
3> 使用analyzer = "ik_max_word"注解,也会报错因为没有引入插件
安装步骤,进入/opt/elasticsearch/plugins文件夹下。
mkdir ik
cd ik
//将插件zip放在该目录下,然后解压
unzip elasticsearch-analysis-ik-6.8.3.zip
//由于我们的是docker部署
将本地linux文件放到docker中
//宿主到docerk
docker cp 本地文件的路径 container_id:<docker容器内的路径>
docker cp /myfiles/services_cq/docker/elasticsearch-analysis-ik-6.8.3.zip 49f6d0ec480f:/opt/elasticsearch/plugins/ik/elasticsearch-analysis-ik-6.8.3.zip
//docekr到宿主
docker cp container_id:<docker容器内的路径> <本地保存文件的路径>
v5.5.1 之后
安装命令,不可以在plugins下面有ik文件夹
直接安装
cd /opt/elasticsearch/bin
//直接install
./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.8.3/elasticsearch-analysis-ik-6.8.3.zip
6. 保存之后查询
本身是这样的,编写查询规则
//远程调用
curl -XGET 'localhost:9200/index/type/_search?pretty' -d '
{
"query": { "match_all": {} },
"from":1,
"size":2
}'
//与上图匹配
GET index/type/_search
{
"query": {
"match_all": {}
}
}
//可以查询多个index和type查询
GET release*/inter_info/_search
{
"query": {
"match_all": {}
}
}
番外二 :query查询语法
// query下一层级主要是说明搜索类型。以何种方式来检索。
match_all 查询全部 (相当于 select * from table)
match 模糊匹配 (相当于 select * from table where A like '%%')
例子:
"query": {
"match": {
"name": "接口"
}
}
match_phrase 全句匹配 (相当于 select * from table where A = B)
muti_match 多字段匹配
query_string 语法查询 用于keyword,直接匹配关键字
term 字查询 为啥是字,因为所有存储的都分为单个字,如果是词则查不到。例如:成都,成,都,都可以查到,但是“成都”查不到
range 范围查询
// 分页,与query同级
from : 10,
size : 10
这里我重启了elasticsearch,发现数据依然在,也就是说该是永久存储在硬盘中的。
elasticsearch引入项目的扩展应用。
1.支持原生的es api查询
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withFilter(boolFilter().must(termFilter("id", documentId)))
.build();
Page<SampleEntity> sampleEntities =
elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
2.使用Scan和Scroll进行大结果集查询
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchAllQuery())
.withIndices("test-index")
.withTypes("test-type")
.withPageable(new PageRequest(0,1))
.build();
String scrollId = elasticsearchTemplate.scan(searchQuery,1000,false);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
boolean hasRecords = true;
while (hasRecords){
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L , new ResultsMapper<SampleEntity>()
{
@Override
public Page<SampleEntity> mapResults(SearchResponse response) {
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
for(SearchHit searchHit : response.getHits()){
if(response.getHits().getHits().length <= 0) {
return null;
}
SampleEntity user = new SampleEntity();
user.setId(searchHit.getId());
user.setMessage((String)searchHit.getSource().get("message"));
chunk.add(user);
}
return new PageImpl<SampleEntity>(chunk);
}
});
if(page != null) {
sampleEntities.addAll(page.getContent());
hasRecords = page.hasNextPage();
}
else{
hasRecords = false;
}
}
}
3.获取client实例进行节点操作,可以自行封装Util方法,client包含节点的所有信息,以及针对请求 或者返回值做处理
4. 从多个索引中检索
基础版:
SearchResponse response = elasticsearchTemplate.getClient().prepareSearch("index1", "index2")
.setTypes("type1", "type2").setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(QueryBuilders.termQuery("name", name)) // Query
.setPostFilter(QueryBuilders.rangeQuery("age").from(12).to(18)) // Filter
.setFrom(0).setSize(60).setExplain(true).get();
return response.toString();
进阶版:
public List<ReleaseDataBean> querBigEsObj(String name) {
QueryBuilder queryBuilder = QueryBuilders.matchPhrasePrefixQuery("name", name);
QueryBuilder builder = QueryBuilders.indicesQuery(queryBuilder, "release");
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(builder).build();
return elasticsearchTemplate.query(searchQuery, resultsExtractor -> {
SearchHits hits = resultsExtractor.getHits();
List<ReleaseDataBean> result = new ArrayList<>();
Arrays.stream(hits.getHits()).forEach(h -> {
Map<String, Object> source = h.getSource();
ReleaseDataBean obj = new ReleaseDataBean();
obj.setId(String.valueOf(source.getOrDefault("id", null)));
result.add(obj);
});
return result;
});
}
1 term query 分词精确查询
QueryBuilder queryBuilder = QueryBuilders.termQuery("name", "华为手机");
2 terms Query 多term查询
QueryBuilder queryBuilder = QueryBuilders.termsQuery("name", "华为手机","摄像机");
3 range query 范围查询
QueryBuilder queryBuilder=QueryBuilders.rangeQuery("price").gte(5000).lt(10000);
4 exist query 查询字段不为null的文档
QueryBuilder queryBuilder= QueryBuilders.existsQuery("introduce");
5 prefix query 匹配分词前缀 如果字段没分词,就匹配整个字段前缀
QueryBuilder queryBuilder=QueryBuilders.prefixQuery("name","华");
6 wildcard query 通配符查询,支持* 任意字符串;?任意一个字符
QueryBuilder queryBuilder=QueryBuilders.wildcardQuery("name","华*");
QueryBuilder queryBuilder=QueryBuilders.wildcardQuery("name","ctr?")
7 regexp query 正则表达式匹配分词,正则表达式自己写吧
QueryBuilder queryBuilder=QueryBuilders.regexpQuery("name","华.*");
8 fuzzy query 分词模糊查询,通过增加fuzziness 模糊属性,来查询term 如下能够匹配 name 为 耳 耳前或后加一个字母的term的 文档 fuzziness 的含义是检索的term 前后增加或减少n个单词的匹配查询,
QueryBuilder queryBuilder=QueryBuilders.fuzzyQuery("name","耳").fuzziness(Fuzziness.ONE);
9 type Query 查询某个type的数据
QueryBuilder queryBuilder=QueryBuilders.typeQuery("digital");