下载
- 访问
https://www.elastic.co/cn/downloads/elasticsearch
本文档编写时最新版本为7.8
- 根据需要选择下载方式
安装
- 解压压缩包
- 进入解压目录 运行
./bin/elasticsearch
启动Elastic,默认9200端口 - 执行命令
curl localhost:9200
请求端口返回说明信息说明启动成功
$: curl localhost:9200
{
"name" : "dfcdd082ff4b",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "qq-dpNhmTpu3pGhE10GJuA",
"version" : {
"number" : "7.8.0",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "757314695644ea9a1dc2fecd26d1a43856725e65",
"build_date" : "2020-06-14T19:35:50.234439Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
- 关闭Elastic,修改
./config/elasticsearch.yml
- 将
network.host
的注释放开,修改为0.0.0.0
允许任何人的访问,线上环境需要设置为具体IP
安装插件
版本Elastic选择对应的版本
ES默认的分词器对中文并不友好,例如“疫情”在使用默认分词器会拆分成"疫"与”情“, 而不是”疫情“。所以需要添加分词器(Analyzer)
- 中文分词器 IK
bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.0/elasticsearch-analysis-ik-7.8.0.zip
- 拼音分词器PINYIN
bin/belasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.8.0/elasticsearch-analysis-ik-7.8.0.zip
- 同义词插件
学习中,想到的场景可以通过NLP做语义分析,构建同义词库,然后通过分词器找关联
基本概念
Node和Cluster
Elastic 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。
单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)
Index
Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。
所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。
下面的命令可以查看当前节点的所有 Index。
$ curl -X GET 'http://localhost:9200/_cat/indices?v'
Document
Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。
Document 使用 JSON 格式表示,下面是一个例子。
{
"user": "张三",
"title": "工程师",
"desc": "数据库管理"
}
同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。
Type
Document 可以分组,比如weather
这个 Index 里面,可以按城市分组(北京和上海),也可以按气候分组(晴天和雨天)。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document。
不同的 Type 应该有相似的结构(schema),举例来说,id
字段不能在这个组是字符串,在另一个组是数值。这是与关系型数据库的表的一个区别。性质完全不同的数据(比如products
和logs
)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)。
下面的命令可以列出每个 Index 所包含的 Type。
$ curl 'localhost:9200/_mapping?pretty=true'
根据规划,Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。
Spring整合
transport使用tcp, restclient使用http。但是 8之后的版本将会去除transport
所以建议根据实际情况选择使用
JavaAPI
引入transport
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
实例化TransportClient
Settings settings = Settings.builder()
.put("cluster.name", "elasticsearch")
.build();
TransportClient client = new PreBuiltTransportClient(settings);
/*
* ES的TCP端口为9300,而不是一般使用的9200
* 这里只配置了一个节点的地址然添加进去,也可以配置多个从节点
*/
InetSocketTransportAddress node = new InetSocketTransportAddress(
InetAddress.getByName("localhost"),9300);
client.addTransportAddress(node);
Spring-Data-ElasticSearch
引入Spring-Data-ElasticSearch
Spring提供的依赖是基于transport,官方建议使用 Hight Level Rest Client
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
</dependency>
定义Document
@Document(indexName = "book")
class Book {
@Id
private Long id;
@Field(searchAnalyzer = "ik_smart", analyzer = "ik_smart")
private String name;
}
@Repository
public interface BookRepository extends ElasticsearchCrudRepository<Book, String> {
}
启用Repositories扫描
@EnableElasticsearchRepositories(basePackages="xxx.xxx.xx")
Rest Client/High Level Rest Client(推荐)
引入RestHightLevelClient
RestHightLevelClient是基于RestClient的高级封装
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.client.version}</version>
</dependency>
配置对应的bean
/**
* ElasticSearch配置类
* 引入对应依赖,且上下文没有配置RestClientBuilder时触发
*
* @author shadow
* @date 2020-06-22 23:20:49
*/
@Configuration
@ConditionalOnClass(RestClientBuilder.class)
@ConditionalOnMissingBean(RestClientBuilder.class)
public class ElasticSearchAutoConfiguration {
@Autowired
private RestClientProperties restClientProperties;
/**
* RestClientBuilder
* @return {@link RestClientBuilder}
*/
@Bean
public RestClientBuilder restClientBuilder() {
List<String> urls = restClientProperties.getUris();
List<HttpHost> httpHosts = new ArrayList<>(urls.size());
for(String uri: urls) {
httpHosts.add(HttpHost.create(uri));
}
return RestClient.builder(httpHosts.toArray(new HttpHost[urls.size()]));
}
/**
* RestClient
* @return {@link RestClient}
*/
@Bean
public RestClient restClient() {
return restClientBuilder().build();
}
/**
* RestHighLevelClient
* @return {@link RestHighLevelClient}
*/
@Bean
public RestHighLevelClient restHighLevelClient() {
return new RestHighLevelClient(restClientBuilder());
}
}
创建索引
PUT /xxxxx
{
"mappings": {
"properties": {
"id": {
"type": "long"
},
"content": {
"type": "text",
"analyzer": "ik_smart"
},
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}
},
"settings": {
"number_of_replicas": 0,
"index": {
"analysis.analyzer.default.type": "ik_max_word",
"analysis.search_analyzer.default.type": "ik_smart"
}
}
}
常用操作
以下都是按照High Level Rest Client编写
创建索引
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
return restHighLevelClient.indices()
.create(createIndexRequest, RequestOptions.DEFAULT)
.index();
增加数据
每条数据都建议赋予一个独立的ID, 方便后续操作
IndexRequest indexRequest = new IndexRequest(index);
indexRequest.id(source.getId());
indexRequest.source(source); // {"id": "123456", "content": "xxxxxx"}
更新数据
IndexRequest indexRequest = new IndexRequest(index);
indexRequest.id(source.getId();
indexRequest.source(source);// {"id": "123456", "content": "yyyyyyy"}
删除数据
DeleteRequest deleteRequest = new DeleteRequest(index);
deleteRequest.id(id);
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
查询数据
TermQuery
模糊查询,完整匹配输入。
类似于正则的
/x/g
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery(field, value));
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
MatchQuery
模糊查询,简单描述与term的区别是会对输入进行分词, 比如上面引入的中文分词,同义词等等。macth也就是一个部分匹配的模糊查询,相对比较宽松
类似于正则的
/.*(x|y).*/g
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery(field, value));
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
MatchPhraseQuery
同MatchQuery,会对输入做分词,但是需要结果中也包含所有的分词,并且顺序要求一致
类似于正则的
/.*x.*y.*z/g
, 并且对结果也做一次校验
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchPhraseQuery(field, value));
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
QueryStringQuery
与match类似,但是不需要指定属性。会在所有字段中搜索,范围更广
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.queryStringQuery(value));
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
BoolQuery
与或非查询,对应Lucene的
BooleanQuery
类似于正则的
/.*(a|b)((c)(d|e)).*/g
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// 添加条件
boolQueryBuilder.must().add(QueryBuilders.matchQuery(key, value));
boolQueryBuilder.should().add(QueryBuilders.matchQuery(key, value));
sourceBuilder.query(boolQueryBuilder);
SearchRequest searchRequest = new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
删除索引
注意,删除索引后,索引下的所有数据一并清除
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
接口定义
接口类
/**
* 搜索服务接口
*
* @param <E> 实现类泛型
* @author shadow
* @version 0.0.1
* @date 2020-02-21
* @since 0.0.1
*/
public interface SearchService<E> {
/**
* 索引是否存在
*
* @param index 索引
* @return true/false
* @throws IOException IO
*/
boolean exists(String index) throws IOException;
/**
* 索引是否存在
*
* @param indices 多索引
* @return true/false
* @throws IOException IO
*/
boolean exists(String... indices) throws IOException;
/**
* 索引
*
* @param index 索引
* @return 索引
* @throws IOException IO
*/
String index(String index) throws IOException;
/**
* 索引
*
* @param index 索引
* @param mappingPath {@link com.hephaestus.search.configuration.ElasticSearchMappingConfig:prefix} 拼接
* @return 索引
* @throws IOException IO
*/
String index(String index, String mappingPath) throws IOException;
/**
* 多索引
*
* @param indices 多索引
* @return 索引组
* @throws IOException IO
*/
String[] index(String... indices) throws IOException;
/**
* 添加文档
*
* @param index 索引
* @param source 源
* @return 索引
* @throws IOException IO
*/
String document(String index, Object source) throws IOException;
/**
* 添加文档
*
* @param indices 多索引
* @return 索引组
* @throws IOException IO
*/
String[] document(Map<String, BaseEntity> indices) throws IOException;
/**
* 删除索引
*
* @param index 索引
* @return true/false
* @throws IOException IO
*/
Boolean delete(String index) throws IOException;
/**
* 删除多索引
*
* @param indices 多索引
* @return true/false
* @throws IOException IO
*/
Boolean delete(String... indices) throws IOException;
/**
* 删除
*
* @param index 索引
* @param id id
* @return true/false
* @throws IOException IO
*/
Boolean delete(String index, String id) throws IOException;
/**
* 条件删除
*
* @param index 索引
* @param key 属性名
* @param value 属性值
* @return 删除个数
* @throws IOException IO
*/
Long queryDelete(String index, String key, String value) throws IOException;
/**
* 搜索
*
* @param index 索引
* @param field 属性名
* @param value 值
* @return {@link SearchHit }
* @throws IOException IO
*/
SearchHit[] search(String index, String field, String value) throws IOException;
/**
* 搜索
*
* @param index 索引
* @param option 条件对象
* @return {@link SearchHit }
* @throws IOException IO
*/
SearchHit[] search(String index, Object option) throws IOException;
/**
* 搜索
*
* @param index 下标
* @param options 多条件数组
* @return {@link SearchHit }
* @throws IOException IO
*/
SearchHit[] search(String index, Object[] options) throws IOException;
/**
* 搜索-根据索引
*
* @param index 索引
* @param field 属性名
* @param value 值
* @return {@link List<String>}
* @throws IOException IO
*/
default List<String> searchByIndex(String index, String field, String value) throws IOException {
SearchHit[] hits = search(index, field, value);
return toList(hits);
}
/**
* 搜索-根据索引
*
* @param index 索引
* @param option 条件对象
* @return {@link List<String>}
* @throws IOException IO
*/
default List<String> searchByIndex(String index, Object option) throws IOException {
SearchHit[] hits = search(index, option);
return toList(hits);
}
/**
* 搜索-根据索引
*
* @param index 索引
* @param options 条件组
* @return {@link List<String>}
* @throws IOException IO
*/
default List<String> searchByIndex(String index, Object[] options) throws IOException {
SearchHit[] hits = search(index, options);
return toList(hits);
}
/**
* 搜索
*
* @param field 属性名
* @param value 值
* @return {@link List<String>}
* @throws IOException IO
*/
default List<String> search(String field, String value) throws IOException {
return searchByIndex(null, field, value);
}
/**
* 搜索
*
* @param option 条件对象
* @return {@link List<String>}
* @throws IOException IO
*/
default List<String> search(Object option) throws IOException {
return searchByIndex(null, option);
}
/**
* 搜索
*
* @param options 条件组
* @return {@link List<String>}
* @throws IOException IO
*/
default List<String> search(Object[] options) throws IOException {
return toList(search(null, options));
}
/**
* 搜索
*
* @param options 条件组
* @param clazz 类
* @param <T> 泛型
* @return {@link List<T>}
* @throws IOException IO
*/
default <T> List<T> search(Object[] options, Class<T> clazz) throws IOException {
return toList(search(options), clazz);
}
/**
* 搜索
*
* @param index 索引
* @param options 条件组
* @param clazz 类
* @param <T> 泛型
* @return {@link List<T>}
* @throws IOException IO
*/
default <T> List<T> search(String index, Object[] options, Class<T> clazz) throws IOException {
return toList(searchByIndex(index, options), clazz);
}
/**
* 搜索
*
* @param option 条件对象
* @param clazz 类
* @param <T> 泛型
* @return {@link List<T>}
* @throws IOException IO
*/
default <T> List<T> search(Object option, Class<T> clazz) throws IOException {
return toList(searchByIndex(null, option), clazz);
}
/**
* 搜索
*
* @param field 属性名
* @param value 值
* @param clazz 类
* @param <T> 泛型
* @return {@link List<T>}
* @throws IOException IO
*/
default <T> List<T> search(String field, String value, Class<T> clazz) throws IOException {
List<String> hits = search(field, value);
return toList(hits, clazz);
}
/**
* 搜索
*
* @param index 索引
* @param field 属性名
* @param value 值
* @param clazz 类
* @param <T> 泛型
* @return {@link List<T>}
* @throws IOException IO
*/
default <T> List<T> search(String index, String field, String value, Class<T> clazz) throws IOException {
List<String> hits = searchByIndex(index, field, value);
return toList(hits, clazz);
}
/**
* 转换为List
*
* @param hits {@link List<SearchHit>}
* @return {@link List<String>} json字符串
*/
default List<String> toList(SearchHit[] hits) {
List<String> results = new ArrayList<>(hits.length);
Arrays.stream(hits).forEach(hit -> results.add(hit.getSourceAsString()));
return results;
}
/**
* 转换为List
*
* @param hits {@link List<SearchHit>}
* @param clazz 类
* @param <T> 泛型
* @return {@link List<T>} 泛型转换
*/
default <T> List<T> toList(List<String> hits, Class<T> clazz) {
List<T> results = new ArrayList<>(hits.size());
hits.forEach(hit -> results.add(JsonUtils.toObject(hit, clazz)));
return results;
}
/**
* 获取搜索实例
*
* @return <E> 实现类
*/
E getOrigin();
}
接口实现
/**
* 搜索服务实现类
* 基于ElasticSearch RestHighLevelClient实现
*
* @author shadow
* @version 0.0.1
* @date 2020-02-21
* @since 0.0.1
*
* <p>
* 压制ali-p3c规范, 不以impl结尾
*/
@SuppressWarnings("AlibabaServiceOrDaoClassShouldEndWithImpl")
@Service
public class ElasticSearchService implements SearchService<RestHighLevelClient> {
private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchService.class);
/** 默认ID属性 */
private static final String FIELD_ID = "id";
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private ElasticSearchMappingConfig elasticSearchMappingConfig;
/**
* 索引是否存在
*
* @param index 索引
* @return true/false
*/
@Override
public boolean exists(String index) throws IOException {
return exists(new String[]{index});
}
/**
* 索引是否存在
*
* @param indices 多索引
* @return true/false
* @throws IOException IO
*/
@Override
public boolean exists(String... indices) throws IOException {
GetIndexRequest getIndexRequest = new GetIndexRequest(indices);
return restHighLevelClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
}
/**
* 索引
*
* @param index 索引
* @return 索引
* @throws IOException IO
*/
@Override
public String index(String index) throws IOException {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
return restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT).index();
}
/**
* 索引
*
* @param index 索引
* @param mappingPath {@link ElasticSearchMappingConfig:prefix} 拼接
* @return 索引
* @throws IOException IO
*/
@Override
public String index(String index, String mappingPath) throws IOException {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
File resource = ResourceUtils.getFile(elasticSearchMappingConfig.getPrefix() + mappingPath);
String source = JSONUtil.readJSON(resource, StandardCharsets.UTF_8).toStringPretty();
createIndexRequest.source(source, XContentType.JSON);
return restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT).index();
}
/**
* 多索引
*
* @param indices 多索引
* @return 索引组
* @throws IOException IO
*/
@Override
public String[] index(String... indices) throws IOException {
BulkRequest bulkRequest = new BulkRequest();
Arrays.stream(indices).forEach(index -> {
IndexRequest indexRequest = new IndexRequest(index);
bulkRequest.add(indexRequest);
});
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
List<String> result = new ArrayList<>(indices.length);
Arrays.stream(bulkResponse.getItems()).forEach(response -> result.add(response.getIndex()));
return result.toArray(new String[indices.length]);
}
/**
* 添加文档
*
* @param index 索引
* @param source 源
* @return 索引
* @throws IOException 1
*/
@Override
public String document(String index, Object source) throws IOException {
IndexRequest indexRequest = new IndexRequest(index);
Object id = BeanUtil.getProperty(source, FIELD_ID);
if (id != null) {
indexRequest.id(id.toString());
}
indexRequest.source(BeanUtil.beanToMap(source));
return restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT).getIndex();
}
/**
* 添加文档
*
* @param indices 多索引
* @return 索引组
* @throws IOException IO
*/
@Override
public String[] document(Map<String, BaseEntity> indices) throws IOException {
BulkRequest bulkRequest = new BulkRequest();
indices.forEach((index, value) -> {
IndexRequest indexRequest = new IndexRequest(index);
indexRequest.source(value);
indexRequest.id(BeanUtil.getProperty(value, FIELD_ID).toString());
bulkRequest.add(indexRequest);
});
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
List<String> result = new ArrayList<>(indices.size());
Arrays.stream(bulkResponse.getItems()).forEach(response -> result.add(response.getIndex()));
return result.toArray(new String[indices.size()]);
}
/**
* 删除
*
* @param index 索引
* @param id id
* @return true/false
* @throws IOException IO
*/
@Override
public Boolean delete(String index, String id) throws IOException {
DeleteRequest deleteRequest = new DeleteRequest(index);
deleteRequest.id(id);
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
return deleteResponse.getId().equals(id);
}
/**
* 删除索引
*
* @param index 索引
* @return true/false
* @throws IOException IO
*/
@Override
public Boolean delete(String index) throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
return acknowledgedResponse.isAcknowledged();
}
/**
* @param indices 多索引
* @return true/false
* @throws IOException IO
*/
@Override
public Boolean delete(String... indices) throws IOException {
BulkRequest bulkRequest = new BulkRequest();
for (String index : indices) {
DeleteRequest deleteRequest = new DeleteRequest(index);
bulkRequest.add(deleteRequest);
}
BulkResponse bulkItemResponses = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return bulkItemResponses.hasFailures();
}
/**
* 条件删除
*
* @param index 索引
* @param key 属性名
* @param value 属性值
* @return 删除个数
* @throws IOException IO
*/
@Override
public Long queryDelete(String index, String key, String value) throws IOException {
DeleteByQueryRequest deleteByQueryRequest = new DeleteByQueryRequest(index);
deleteByQueryRequest.setQuery(new TermQueryBuilder(key, value));
BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.deleteByQuery(deleteByQueryRequest, RequestOptions.DEFAULT);
return bulkByScrollResponse.getTotal();
}
/**
* 搜索
*
* @param index 索引
* @param field 属性名
* @param value 值
* @return {@link SearchHit }
* @throws IOException IO
*/
@Override
public SearchHit[] search(String index, String field, String value) throws IOException {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery(field, value));
SearchRequest searchRequest = index == null ? new SearchRequest() : new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
return searchResponse.getHits().getHits();
}
/**
* 搜索
*
* @param index 索引
* @param option 条件对象
* @return {@link SearchHit }
* @throws IOException IO
*/
@Override
public SearchHit[] search(String index, Object option) throws IOException {
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
BeanUtil.beanToMap(option).forEach((key, value) -> {
if (value != null) {
boolQueryBuilder.must().add(QueryBuilders.matchQuery(key, value));
}
});
sourceBuilder.query(boolQueryBuilder);
SearchRequest searchRequest = index == null ? new SearchRequest() : new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
return searchResponse.getHits().getHits();
}
/**
* 搜索
* @param index 下标
* @param options 多条件数组
* @return {@link SearchHit }
* @throws IOException IO
*/
@Override
public SearchHit[] search(String index, Object[] options) throws IOException{
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// 数组forEach循环,然后将对象转为Map,null值跳过
Arrays.stream(options).forEach(option -> BeanUtil.beanToMap(option).forEach((key, value) -> {
if (value != null) {
boolQueryBuilder.must().add(QueryBuilders.matchQuery(key, value));
}
}));
sourceBuilder.query(boolQueryBuilder);
SearchRequest searchRequest = index == null ? new SearchRequest() : new SearchRequest(index);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
return searchResponse.getHits().getHits();
}
/**
* 获取搜索实例
*
* @return T 搜索实例
*/
@Override
public RestHighLevelClient getOrigin() {
return restHighLevelClient;
}
}
可视化工具
Elastic HD
下载地址
参考文献
中文文档基于ElasticSearch2.x版本,可能部分内容已经过时,建议阅读较新的原文版本