简介

类比mysql等关系型数据库,elasticsearch这种nosql的搜索引擎效率更快,通常的案例有百度淘宝等即时搜索功能
Relational DB -> Databases -> Tables -> Rows -> Columns
关系型数据库 数据库 表 行 列
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch 索引 类型 文档 域(字段)

elasticsearch安装(windows)

  1. 官网下载压缩包
  2. 解压缩
  3. 运行bin目录下的elasticsearch.bat批处理文件
  4. cd到对应目录在dos命令行elasticsearch-service.bat install安装elasticsearch服务
  5. 访问localhost:9200(默认端口)

kibana可视化工具安装(windows)

  1. 官网下载压缩包
  2. 解压缩
  3. 运行bin目录下的kibana.bat(git-bash可用cmd.exe /C kibana运行)
  4. 访问localhost:5601(默认端口)

elasticsearch在java中的使用方式

RestHighLevelClient的使用

RestHighLevelClient即是Elasticsearch的一个高级客户端,对Elasticsearch集群的所有操作都要经过该客户端来操作。其在java中可通过低级客户端RestClient来获得。

public RestHighLevelClient(RestClientBuilder restClientBuilder) {
this(restClientBuilder, Collections.emptyList());
}

对索引Index的操作

创建索引

elasticsearch中索引就是类似数据库的结构,我们可通过创建一个CreateIndexRequest,让客户端来执行创建请求

CreateIndexRequest request=new CreateIndexRequest("new_index");
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
//获得创建结果:boolean
System.out.println(response.isAcknowledged());

同时也可对CreateIndexRequest的各种设置参数的方法来对所创建的索引结构进行设置(如分词器,过滤器等),此处不再一一说明。

判断索引是否存在

public boolean existIndex(String index) {
GetIndexRequest request=new GetIndexRequest(index);
try {
return client.indices().exists(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}

删除索引

public boolean deleteIndex(String index) {
//先判断是否存在
if(!existIndex(index)){
return false;
}
DeleteIndexRequest request=new DeleteIndexRequest(index);
try {
AcknowledgedResponse response = client.indices().delete(request,
RequestOptions.DEFAULT);
return response.isAcknowledged();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}

对文档Document的操作

文档document类比数据库中的行,元组,通常搜索出来的元数据结果就是以每个文档为单位。每个文档都有特定的id,所以以下与特定文档相关的方法都会包含id这个参数

创建文档

/**
*index:索引的名称
*id:在索引中设置的id(如果不手动设也可以,会自动分配id)
*content:向index中添加的document元组,格式为json
**/
public boolean createDocument(String index, String id, String content) {
//查看文档是否存在
if(existDocument(index,id)){
return false;
}
IndexRequest request=new IndexRequest(index).id(id);
request.source(content, XContentType.JSON);
IndexResponse response = null;
try {
response = client.index(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return (response.status()==RestStatus.CREATED);
}

判断文档是否存在

public boolean existDocument(String index, String id){
GetRequest request=new GetRequest(index,id);
try {
return client.exists(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return false;
}

获取文档

/**
*这里获得的返回结果为json字符串
**/
public String getDocument(String index, String id) {
GetRequest request=new GetRequest(index,id);
GetResponse response = null;
try {
response = client.get(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return response.getSourceAsString();
}

更新文档

public boolean updateDocument(String index, String id, String content) {
//判断文档是否存在
if(!existDocument(index,id)){
return false;
}
UpdateRequest request=new UpdateRequest(index,id);
request.doc(content,XContentType.JSON);
UpdateResponse response = null;
try {
response = client.update(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return (response.status()==RestStatus.OK);
}

删除文档

public boolean deleteDocument(String index, String id) {
if(!existDocument(index,id)){
return false;
}
DeleteRequest request=new DeleteRequest(index,id);
DeleteResponse response = null;
try {
response = client.delete(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
return (response.status()==RestStatus.OK);
}

批量操作

我们可以通过BulkRequest来对多个DocWriteRequest(DeleteRequest,IndexRequest,UpdateRequest)操作进行添加集成,然后统一让RestHighLevelClient执行对文档的批量操作,下面封装了一个进行批量操作的方法

public boolean bulkRequest(String index, Iterable<DocWriteRequest<?>> requests) {
BulkRequest bulkRequest=new BulkRequest();
requests.forEach(x->{
bulkRequest.add(x);
});
BulkResponse responses = null;
try {
responses = client.bulk(bulkRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
BulkItemResponse[] items = responses.getItems();
for(BulkItemResponse tmp:items){
System.out.println("操作:"+tmp.getOpType().name()+"-主键id:"+tmp.getId()+"-是否成功:"+(!tmp.isFailed()));
}
return !responses.hasFailures();
}

使用用例

@Test
void testBulkOperation(){
//添加document操作
IndexRequest indexRequest=new IndexRequest("desktop").id("testId")
.source(XContentType.JSON,"testField1","testField1");
//修改document操作
JSONObject jsonObject=new JSONObject();
jsonObject.put("programId","5");
jsonObject.put("programName","网易云音乐-updated");
UpdateRequest updateRequest=new UpdateRequest("desktop","1006")
.doc(jsonObject.toJSONString(),XContentType.JSON);
//操作集合
List<DocWriteRequest<?>>requests=new ArrayList<>();
requests.add(indexRequest);
requests.add(updateRequest);
System.out.println(service.bulkRequest("desktop",requests));
}

对多个索引中特定的字段进行关键字查找

/**
*要设置查找的字段也可以当成参数传递进来,懒得改了
**/
public List<JSONObject> searchByKeyword(String keyword,String...indices) {
List<JSONObject>results=null;
SearchRequest request=new SearchRequest();
request.indices(indices);
SearchSourceBuilder builder=new SearchSourceBuilder();
//设置查找字段
builder.query(QueryBuilders.multiMatchQuery(keyword,"programName","tag","username")
.fuzziness(Fuzziness.AUTO));
request.source(builder);
SearchResponse response = null;
try {
response = client.search(request, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
SearchHit[] hits = response.getHits().getHits();
if(hits.length>0){
results=new ArrayList<>();
for(SearchHit hit:hits){
JSONObject jsonObject=JSONObject.parseObject(hit.getSourceAsString());
results.add(jsonObject);
}
}
return results;
}

使用账号密码连接elasticsaerch

通常默认情况下es本地是不设账号密码的,可直接通过localhost:9200访问,但是也可以设置密码来加强es的安全性

修改elasticsearch.yml配置文件

使用xpack给es添加安全支持,同时允许http请求跨域,在elasticsearch.yml文件中添加以下配置

http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true

执行自定义密码的命令

cd到es的bin目录下,执行elasticsearch-setup-passwords interactive,按照提示分别给几个系统都设置密码

通过kibana或localhost:9200访问测试

启动kibana/elasticsearch服务,在访问lcalhost:5601/localhost:9200时输入es账号密码,默认账号为elastic

修改密码的curl命令

POST /_security/user/{username}/_password
{
"password": "your password"
}

在Java中通过api连接

我们通常使用的是RestHighLevelClient,其可通过低级客户端的构造器RestClientBuilder获得,根据官方文档的指引,我们可通过设置http客户端的配置来设置账号密码最后构建RestClientBuilder

@Bean
public RestClientBuilder restClientBuilder(){
final CredentialsProvider credentialsProvider =
new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(username, password));
RestClientBuilder builder=RestClient.builder(new HttpHost(host,port,protocol));
builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
httpAsyncClientBuilder.disableAuthCaching();
return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
});
return builder;
}

@Bean(name = "restHighLevelClient")
public RestHighLevelClient restHighLevelClient(@Autowired RestClientBuilder restClientBuilder){
return new RestHighLevelClient(restClientBuilder);
}