初始化
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.easyagents</groupId>
|
||||
<artifactId>easy-agents-search-engine</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<name>easy-agents-search-engine-es</name>
|
||||
<artifactId>easy-agents-search-engine-es</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.easyagents</groupId>
|
||||
<artifactId>easy-agents-search-engine-service</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.easyagents</groupId>
|
||||
<artifactId>easy-agents-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>co.elastic.clients</groupId>
|
||||
<artifactId>elasticsearch-java</artifactId>
|
||||
<version>8.15.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.15.2</version> <!-- 或与Elasticsearch客户端兼容的版本 -->
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2023-2026, Easy-Agents (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.easyagents.engine.es;
|
||||
|
||||
public class ESConfig {
|
||||
private String host;
|
||||
private String userName;
|
||||
private String password;
|
||||
private String indexName;
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
public void setIndexName(String indexName) {
|
||||
this.indexName = indexName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package com.easyagents.engine.es;
|
||||
|
||||
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||
import co.elastic.clients.elasticsearch.core.*;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
|
||||
import co.elastic.clients.elasticsearch.core.bulk.IndexOperation;
|
||||
import co.elastic.clients.json.JsonData;
|
||||
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.easyagents.search.engine.service.DocumentSearcher;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.impl.client.BasicCredentialsProvider;
|
||||
import org.elasticsearch.client.RestClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.*;
|
||||
|
||||
public class ElasticSearcher implements DocumentSearcher {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ElasticSearcher.class);
|
||||
|
||||
private final ESConfig esConfig;
|
||||
|
||||
public ElasticSearcher(ESConfig esConfig) {
|
||||
this.esConfig = esConfig;
|
||||
}
|
||||
|
||||
// 忽略 SSL 的 client 构建逻辑
|
||||
private RestClient buildRestClient() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
TrustManager[] trustAllCerts = new TrustManager[]{
|
||||
new X509TrustManager() {
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void checkClientTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
|
||||
public void checkServerTrusted(X509Certificate[] certs, String authType) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
|
||||
|
||||
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
|
||||
credentialsProvider.setCredentials(
|
||||
AuthScope.ANY,
|
||||
new UsernamePasswordCredentials(esConfig.getUserName(), esConfig.getPassword()));
|
||||
|
||||
return RestClient.builder(HttpHost.create(esConfig.getHost()))
|
||||
.setHttpClientConfigCallback(httpClientBuilder -> {
|
||||
httpClientBuilder.setSSLContext(sslContext);
|
||||
httpClientBuilder.setSSLHostnameVerifier((hostname, session) -> true);
|
||||
httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
|
||||
return httpClientBuilder;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加文档到Elasticsearch
|
||||
*/
|
||||
@Override
|
||||
public boolean addDocument(Document document) {
|
||||
if (document == null || document.getContent() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RestClient restClient = null;
|
||||
ElasticsearchTransport transport = null;
|
||||
try {
|
||||
restClient = buildRestClient();
|
||||
transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
|
||||
ElasticsearchClient client = new ElasticsearchClient(transport);
|
||||
|
||||
Map<String, Object> source = new HashMap<>();
|
||||
source.put("id", document.getId());
|
||||
source.put("content", document.getContent());
|
||||
if (document.getTitle() != null) {
|
||||
source.put("title", document.getTitle());
|
||||
}
|
||||
|
||||
String documentId = document.getId().toString();
|
||||
IndexOperation<?> indexOp = IndexOperation.of(i -> i
|
||||
.index(esConfig.getIndexName())
|
||||
.id(documentId)
|
||||
.document(JsonData.of(source))
|
||||
);
|
||||
|
||||
BulkOperation bulkOp = BulkOperation.of(b -> b.index(indexOp));
|
||||
BulkRequest request = BulkRequest.of(b -> b.operations(Collections.singletonList(bulkOp)));
|
||||
BulkResponse response = client.bulk(request);
|
||||
return !response.errors();
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
return false;
|
||||
} finally {
|
||||
closeResources(transport, restClient);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Document> searchDocuments(String keyword, int count) {
|
||||
RestClient restClient = null;
|
||||
ElasticsearchTransport transport = null;
|
||||
|
||||
try {
|
||||
restClient = buildRestClient();
|
||||
transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
|
||||
ElasticsearchClient client = new ElasticsearchClient(transport);
|
||||
|
||||
SearchRequest request = SearchRequest.of(s -> s
|
||||
.index(esConfig.getIndexName())
|
||||
.size(count)
|
||||
.query(q -> q
|
||||
.match(m -> m
|
||||
.field("title")
|
||||
.field("content")
|
||||
.query(keyword)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
SearchResponse<Document> response = client.search(request, Document.class);
|
||||
List<Document> results = new ArrayList<>();
|
||||
response.hits().hits().forEach(hit -> results.add(hit.source()));
|
||||
return results;
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
return Collections.emptyList();
|
||||
} finally {
|
||||
closeResources(transport, restClient);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteDocument(Object id) {
|
||||
if (id == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RestClient restClient = null;
|
||||
ElasticsearchTransport transport = null;
|
||||
try {
|
||||
restClient = buildRestClient();
|
||||
transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
|
||||
ElasticsearchClient client = new ElasticsearchClient(transport);
|
||||
|
||||
DeleteRequest request = DeleteRequest.of(d -> d
|
||||
.index(esConfig.getIndexName())
|
||||
.id(id.toString())
|
||||
);
|
||||
|
||||
DeleteResponse response = client.delete(request);
|
||||
return response.result() == co.elastic.clients.elasticsearch._types.Result.Deleted;
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error deleting document with id: " + id, e);
|
||||
return false;
|
||||
} finally {
|
||||
closeResources(transport, restClient);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateDocument(Document document) {
|
||||
if (document == null || document.getId() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RestClient restClient = null;
|
||||
ElasticsearchTransport transport = null;
|
||||
|
||||
try {
|
||||
restClient = buildRestClient();
|
||||
transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
|
||||
ElasticsearchClient client = new ElasticsearchClient(transport);
|
||||
|
||||
UpdateRequest<Document, Object> request = UpdateRequest.of(u -> u
|
||||
.index(esConfig.getIndexName())
|
||||
.id(document.getId().toString())
|
||||
.doc(document)
|
||||
);
|
||||
|
||||
UpdateResponse<Document> response = client.update(request, Object.class);
|
||||
return response.result() == co.elastic.clients.elasticsearch._types.Result.Updated;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error updating document with id: " + document.getId(), e);
|
||||
return false;
|
||||
} finally {
|
||||
closeResources(transport, restClient);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void closeResources(AutoCloseable... closeables) {
|
||||
for (AutoCloseable closeable : closeables) {
|
||||
try {
|
||||
if (closeable != null)
|
||||
closeable.close();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error closing resource", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.easyagents.search.engines.es;
|
||||
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.easyagents.engine.es.ESConfig;
|
||||
import com.easyagents.engine.es.ElasticSearcher;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class ElasticSearcherTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
// 创建工具类实例 (忽略SSL证书,如果有认证则提供用户名密码)
|
||||
ESConfig searcherConfig = new ESConfig();
|
||||
searcherConfig.setHost("https://127.0.0.1:9200");
|
||||
searcherConfig.setUserName("elastic");
|
||||
searcherConfig.setPassword("elastic");
|
||||
searcherConfig.setIndexName("aiknowledge");
|
||||
ElasticSearcher esUtil = new ElasticSearcher(searcherConfig);
|
||||
Document document1 = new Document();
|
||||
document1.setContent("平台客服工具:是指拼多多平台开发并向商家提供的功能或工具,商家通过其专属账号登录平台客服工具后,可以与平台消费者取得\\n\" +\n" +
|
||||
" \"联系并为消费者提供客户服务");
|
||||
document1.setId(BigInteger.valueOf(1));
|
||||
esUtil.addDocument(document1);
|
||||
|
||||
Document document2 = new Document();
|
||||
document2.setId(2);
|
||||
document2.setContent("document 2 的内容");
|
||||
document2.setTitle("document 2");
|
||||
esUtil.addDocument(document2);
|
||||
|
||||
System.out.println("查询开始--------");
|
||||
List<Document> res = esUtil.searchDocuments("客服");
|
||||
res.forEach(System.out::println);
|
||||
System.out.println("查询结束--------");
|
||||
|
||||
document1.setTitle("document 3");
|
||||
esUtil.updateDocument(document1);
|
||||
|
||||
// esUtil.deleteDocument(1);
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user