ElasticSearch 简介
1. 概述
在本文中,我们将深入探讨与全文搜索引擎相关的一些关键概念,特别关注 Elasticsearch。
由于这是一篇面向 Java 的文章,我们不会提供有关如何设置 Elasticsearch 并展示它如何在幕后工作的详细分步教程。相反,我们将针对 Java 客户端,以及如何使用主要功能,如index、delete、get和search。
2. 设置
为简单起见,我们将为我们的 Elasticsearch 实例使用 docker 映像,尽管任何侦听端口 9200 的 Elasticsearch 实例都可以。
我们首先启动我们的 Elasticsearch 实例:
docker run -d --name es762 -p 9200:9200 -e "discovery.type=single-node" elasticsearch:7.6.2
默认情况下,Elasticsearch 在 9200 端口上侦听即将到来的 HTTP 查询。我们可以通过在您喜欢的浏览器中打开http://localhost:9200/ URL来验证它是否已成功启动:
{
"name" : "M4ojISw",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "CNnjvDZzRqeVP-B04D3CmA",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "2f4c224",
"build_date" : "2020-03-18T23:22:18.622755Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.8.0-beta1"
},
"tagline" : "You Know, for Search"
}
3. Maven配置
现在我们已经启动并运行了基本的 Elasticsearch 集群,让我们直接跳到 Java 客户端。首先,我们需要在pom.xml文件中声明以下Maven 依赖项 :
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.6.2</version>
</dependency>
您可以随时通过之前提供的链接查看 Maven Central 托管的最新版本。
4. Java API
在我们直接跳到如何使用主要的 Java API 功能之前,我们需要启动RestHighLevelClient:
ClientConfiguration clientConfiguration =
ClientConfiguration.builder().connectedTo("localhost:9200").build();
RestHighLevelClient client = RestClients.create(clientConfiguration).rest();
4.1.索引文件
*index()*函数允许存储任意 JSON 文档并使其可搜索:
@Test
public void givenJsonString_whenJavaObject_thenIndexDocument() {
String jsonObject = "{\"age\":10,\"dateOfBirth\":1471466076564,"
+"\"fullName\":\"John Doe\"}";
IndexRequest request = new IndexRequest("people");
request.source(jsonObject, XContentType.JSON);
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
String index = response.getIndex();
long version = response.getVersion();
assertEquals(Result.CREATED, response.getResult());
assertEquals(1, version);
assertEquals("people", index);
}
请注意,可以使用**任何 JSON Java 库 **来创建和处理您的文档。如果你不熟悉这些,你可以使用 Elasticsearch 助手来生成你自己的 JSON 文档:
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("fullName", "Test")
.field("dateOfBirth", new Date())
.field("age", "10")
.endObject();
IndexRequest indexRequest = new IndexRequest("people");
indexRequest.source(builder);
IndexResponse response = client.index(indexRequest, RequestOptions.DEFAULT);
assertEquals(Result.CREATED, response.getResult());
4.2. 查询索引文档
现在我们已经索引了一个键入的可搜索 JSON 文档,我们可以继续使用*search()*方法进行搜索:
SearchRequest searchRequest = new SearchRequest();
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHit[] searchHits = response.getHits().getHits();
List<Person> results =
Arrays.stream(searchHits)
.map(hit -> JSON.parseObject(hit.getSourceAsString(), Person.class))
.collect(Collectors.toList());
search()方法返回的结果称为Hits,每个Hit引用一个匹配搜索请求的 JSON 文档。
在这种情况下,results列表包含存储在集群中的所有数据。请注意,在此示例中,我们使用FastJson 库将 JSON string转换为 Java 对象。
我们可以通过添加其他参数来增强请求,以便使用QueryBuilders方法自定义查询:
SearchSourceBuilder builder = new SearchSourceBuilder()
.postFilter(QueryBuilders.rangeQuery("age").from(5).to(15));
SearchRequest searchRequest = new SearchRequest();
searchRequest.searchType(SearchType.DFS_QUERY_THEN_FETCH);
searchRequest.source(builder);
SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
4.3. 检索和删除文档
*get()*和 *delete()*方法允许使用其id 从集群中获取或删除 JSON 文档:
GetRequest getRequest = new GetRequest("people");
getRequest.id(id);
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
// process fields
DeleteRequest deleteRequest = new DeleteRequest("people");
deleteRequest.id(id);
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
语法非常简单,您只需要在对象的 id 旁边指定索引。
5. QueryBuilders示例
QueryBuilders类提供了多种静态方法,用作动态匹配器来查找集群中的特定条目。在使用*search()*方法在集群中查找特定的 JSON 文档时,我们可以使用查询构建器来自定义搜索结果。
以下是QueryBuilders API最常见用途的列表。
matchAllQuery()方法返回一个匹配集群中所有文档的QueryBuilder对象:
QueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();
*rangeQuery()*匹配字段值在特定范围内的文档:
QueryBuilder matchDocumentsWithinRange = QueryBuilders
.rangeQuery("price").from(15).to(100)
提供一个字段名称 - 例如fullName和相应的值 - 例如John Doe,*matchQuery()*方法匹配所有具有这些确切字段值的文档:
QueryBuilder matchSpecificFieldQuery= QueryBuilders
.matchQuery("fullName", "John Doe");
我们也可以使用*multiMatchQuery()*方法来构建匹配查询的多字段版本:
QueryBuilder matchSpecificFieldQuery= QueryBuilders.matchQuery(
"Text I am looking for", "field_1", "field_2^3", "*_field_wildcard");
我们可以使用插入符号 (^) 来提升特定字段。
在我们的示例中,field_2 的 boost 值设置为 3,使其比其他字段更重要。请注意,可以使用通配符和正则表达式查询,但在性能方面,处理通配符时要注意内存消耗和响应时间延迟,因为像 *_apples 这样的东西可能会对性能产生巨大影响。
重要性系数用于对执行*search()*方法后返回的命中结果集进行排序。
如果您更熟悉 Lucene 查询语法,可以使用*simpleQueryStringQuery()*方法自定义搜索查询:
QueryBuilder simpleStringQuery = QueryBuilders
.simpleQueryStringQuery("+John -Doe OR Janette");
正如您可能猜到的,我们可以使用 Lucene 的 Query Parser 语法来构建简单但功能强大的查询。以下是一些可与AND/OR/NOT运算符一起用于构建搜索查询的基本运算符:
- 必需的运算符 ( + ):要求在文档的字段中某处存在特定的一段文本。
- 禁止运算符 ( - ):排除所有包含在 ( - ) 符号后声明的关键字的文档。