Elasticsearch介绍
Elasticsearch是一个开源的搜索引擎,它可以实现全文检索、分布式搜索、分析等功能。它使用Lucene作为搜索引擎的核心,通过HTTP RESTful API提供数据索引和搜索服务。Elasticsearch被广泛应用于企业搜索、日志分析、安全分析等领域。本文将介绍如何入门Elasticsearch。
Elasticsearch的倒排索引
Elasticsearch是一种基于Lucene的分布式搜索引擎,它使用倒排索引(Inverted Index)来加速搜索。倒排索引是一种数据结构,它将文档中的每个单词映射到包含该单词的文档列表中,以便快速地进行文本搜索。
在传统的索引中,文档是按照文档ID进行排序的,而倒排索引则是按照单词进行排序的。举例来说,如果有两篇文档,其中一篇包含单词“Elasticsearch”,另一篇包含单词“Java”,那么倒排索引将会是这样的:
Elasticsearch -> Doc1
Java -> Doc2
这样的索引结构使得搜索引擎能够快速地找到包含特定单词的文档,并将它们按照相关性排序。在搜索一个查询时,搜索引擎只需要找到查询中包含的单词所对应的文档列表,并对这些文档进行排序,然后返回排名最高的文档即可。
倒排索引的优点是它可以快速地找到包含特定单词的文档,而不需要遍历整个文档集合。这使得搜索引擎能够处理大量的文档,并在短时间内响应查询请求。在Elasticsearch中,倒排索引是通过Lucene实现的,而且它可以处理多种类型的数据,包括文本、数字、地理位置等。
安装Elasticsearch
Elasticsearch支持多种操作系统,包括Windows、Linux、Mac OS等。以下是在Linux上安装
Elasticsearch的步骤:
下载Elasticsearch的安装包,可以从Elasticsearch官网(https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.12.0-windows-x86_64.zip)下载。
解压安装包,执行以下命令:
tar -zxvf elasticsearch-7.6.1-linux-x86_64.tar.gz
进入Elasticsearch的bin目录,启动Elasticsearch:
cd elasticsearch-7.6.1/bin
./elasticsearch
执行以下命令,测试Elasticsearch是否正常运行:
curl http://localhost:9200/
如果返回类似以下结果,则表示Elasticsearch已成功安装:
{
"name" : "node-1",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "n8Jy9VbTRtWJ8z4HJ0jQ8g",
"version" : {
"number" : "7.6.1",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "aa751e09be0a5072e8570670309b1f12348f023b",
"build_date" : "2020-02-29T00:15:25.529771Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
使用Elasticsearch
创建索引
Elasticsearch中的数据存储在索引中,可以将索引看做是关系型数据库中的表。以下是创建一个名为test的索引的步骤:
执行以下命令,创建名为test的索引:
curl -X PUT "localhost:9200/test?pretty"
如果返回类似以下结果,则表示索引已成功创建:
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "test"
}
在索引中添加数据:
curl -X PUT "localhost:9200/test/_doc/1?pretty" -H 'Content-Type: application/json' -d'
{
"title": "Elasticsearch",
"author": "John Doe",
"content": "Elasticsearch is a search engine based on Lucene."
}
如果返回类似以下结果,则表示数据已成功添加到索引中:
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
搜索
执行以下命令,搜索包含“Elasticsearch”的数据:
curl -X GET "localhost:9200/test/_search?q=Elasticsearch&pretty"
如果返回类似以下结果,则表示搜索结果:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"title" : "Elasticsearch",
"author" : "John Doe",
"content" : "Elasticsearch is a search engine based on Lucene."
}
}
]
}
}
执行以下命令,搜索包含“search engine”的数据:
curl -X GET "localhost:9200/test/_search" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"content": "search engine"
}
}
}
如果返回类似以下结果,则表示搜索结果:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"title" : "Elasticsearch",
"author" : "John Doe",
"content" : "Elasticsearch is a search engine based on Lucene."
}
}
]
}
}
Springboot集成Elasticsearch
添加Elasticsearch依赖
在pom.xml文件中添加Elasticsearch依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
配置Elasticsearch
在application.properties文件中添加Elasticsearch的配置信息:
spring.data.elasticsearch.cluster-name=my-application
spring.data.elasticsearch.cluster-nodes=localhost:9300
创建实体类
创建一个实体类,表示要在Elasticsearch中存储的数据。
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Document(indexName = "book", type = "book")
public class Book {
@Id
private String id;
private String title;
private String author;
private String content;
}
@Data:Lombok注解,自动生成getter、setter、equals、hashCode和toString方法。
@NoArgsConstructor:Lombok注解,自动生成无参构造函数。
@AllArgsConstructor:Lombok注解,自动生成全参构造函数。
@Builder:Lombok注解,自动生成builder方法。
@Document:Elasticsearch注解,指定索引名称和类型。
@Id:Elasticsearch注解,指定文档ID。
创建Elasticsearch仓库
创建一个继承自ElasticsearchRepository的接口。
public interface BookRepository extends ElasticsearchRepository<Book, String> {
}
ElasticsearchRepository是Spring Data Elasticsearch提供的仓库接口,它提供了一些基本的CRUD操作。
使用Elasticsearch
在业务代码中使用BookRepository接口操作Elasticsearch。
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
private BookRepository bookRepository;
@PostMapping("/")
public Book save(@RequestBody Book book) {
return bookRepository.save(book);
}
@GetMapping("/{id}")
public Optional<Book> findById(@PathVariable String id) {
return bookRepository.findById(id);
}
@GetMapping("/")
public Iterable<Book> findAll() {
return bookRepository.findAll();
}
@GetMapping("/search")
public Iterable<Book> search(@RequestParam String keyword) {
String wildcardQuery = String.format("*%s*", keyword);
QueryStringQueryBuilder builder = QueryBuilders.queryStringQuery(wildcardQuery);
Iterable<Book> books = bookRepository.search(builder);
return books;
}
}
@RestController:Spring MVC注解,标识这是一个RESTful接口。
@RequestMapping(“/book”):Spring MVC注解,指定接口的URL路径。
@Autowired:Spring注解,自动注入依赖。
@PostMapping(“/”):Spring MVC注解,指定POST请求的URL路径。
@RequestBody:Spring MVC注解,将请求体转换成Java对象。
@GetMapping(“/{id}”):Spring MVC注解,指定GET请求的URL路径,使用{id}占位符表示参数。
@PathVariable:Spring MVC注解,将URL中的参数映射到方法的参数中。
@GetMapping(“/”):Spring MVC注解,指定GET请求的URL路径。
@RequestParam:Spring MVC注解,将URL中的参数映射到方法的参数中。
QueryStringQueryBuilder:Elasticsearch查询构建器,用于构建查询语句。
QueryBuilders.queryStringQuery(wildcardQuery):创建一个查询字符串查询。
Elasticsearch三种分页查询方法
方法一:使用from和size参数
Elasticsearch的from和size参数可以用来控制查询结果的分页。from参数指定开始返回结果的位置,size参数指定返回结果的数量。例如,如果要查询第11个到第20个结果,可以设置from=10,size=10。
在Java中,可以使用Elasticsearch的SearchRequestBuilder来设置from和size参数。
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index)
.setTypes(type)
.setQuery(QueryBuilders.matchAllQuery())
.setFrom(0)
.setSize(10);
SearchResponse response = searchRequestBuilder.get();
上面的代码将查询第1页的结果,每页返回10条数据。
方法二:使用scroll API
Elasticsearch的scroll API可以用来处理大量数据的分页查询。它的工作原理是,先查询一次,获取第一页的数据,并返回一个scroll_id;然后,使用scroll_id来获取下一页的数据,直到数据全部查询完毕。scroll API的优点是可以处理大量数据的分页查询,并且每个分页查询的时间相对稳定。
在Java中,可以使用Elasticsearch的SearchScrollRequestBuilder来实现scroll API的分页查询。
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index)
.setTypes(type)
.setQuery(QueryBuilders.matchAllQuery())
.setScroll(new TimeValue(60000))
.setSize(10);
SearchResponse response = searchRequestBuilder.get();
String scrollId = response.getScrollId();
while (true) {
SearchScrollRequestBuilder scrollRequestBuilder = client.prepareSearchScroll(scrollId)
.setScroll(new TimeValue(60000));
SearchResponse scrollResponse = scrollRequestBuilder.get();
scrollId = scrollResponse.getScrollId();
SearchHits hits = scrollResponse.getHits();
if (hits.getHits().length == 0) {
break;
}
for (SearchHit hit : hits.getHits()) {
// 处理每一条数据
}
}
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
clearScrollRequest.addScrollId(scrollId);
client.clearScroll(clearScrollRequest);
上面的代码将查询所有的结果,并对每个结果进行处理。
方法三:使用分片查询
Elasticsearch的分片查询可以用来加速分页查询。它的工作原理是,将索引分成多个分片,每个分片都可以独立处理查询请求。当查询请求到达时,Elasticsearch会将请求分发到多个分片上,并将每个分片的查询结果合并起来。分片查询的优点是可以加速分页查询,并且可以处理大量数据的分页查询。
在Java中,可以使用Elasticsearch的SearchRequestBuilder来实现分片查询的分页查询。
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(index)
.setTypes(type)
.setQuery(QueryBuilders.matchAllQuery())
.setFrom(0)
.setSize(10)
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
SearchResponse response = searchRequestBuilder.get();
SearchHits hits = response.getHits();
for (SearchHit hit : hits.getHits()) {
// 处理每一条数据
}
上面的代码将使用分片查询来查询第1页的结果,每页返回10条数据。
Elasticsearch的排序和权重设置
Elasticsearch的排序和权重设置可以通过查询时设置排序字段和排序方式,以及设置查询条件的权重来实现。
排序设置
可以使用Elasticsearch的查询API实现排序设置,例如使用SearchRequestBuilder的addSort方法,设置排序字段和排序方式,如下所示:
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("index");
searchRequestBuilder.setTypes("type");
searchRequestBuilder.addSort("field", SortOrder.DESC);
上述代码中,设置了按照“field”字段进行倒序排序,也可以设置为SortOrder.ASC进行升序排序。
权重设置
可以使用Elasticsearch的查询API实现查询条件的权重设置,例如使用QueryBuilder的boost方法,为查询条件设置权重,如下所示:
QueryBuilder queryBuilder = QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("field1", "value1").boost(2.0f))
.should(QueryBuilders.matchQuery("field2", "value2").boost(1.0f));
上述代码中,设置了对“field1”字段的查询权重为2.0,对“field2”字段的查询权重为1.0。这意味着匹配“field1”字段的文档将比匹配“field2”字段的文档更加相关。
Elasticsearch查询优化
-
选择合适的查询类型
Elasticsearch提供了多种查询类型,如Match Query、Term Query、Range Query等。不同的查询类型适用于不同的场景,选择合适的查询类型可以提高查询性能。 -
设置合适的分片数量和大小
Elasticsearch将索引分为多个分片,分片数量和大小对查询性能有重要影响。如果分片过多,每个分片的大小会变小,但是查询时需要访问更多的分片,会降低查询性能。如果分片过少,每个分片的大小会变大,但是会导致集群负载不均衡。因此,需要根据实际情况选择合适的分片数量和大小。 -
缓存查询结果
Elasticsearch提供了缓存查询结果的功能,可以减少相同查询的响应时间。可以将经常使用的查询结果缓存起来,以提高查询性能。 -
使用搜索建议
Elasticsearch提供了搜索建议(Suggest)功能,可以为用户提供实时的查询建议。搜索建议可以降低用户的查询次数,提高用户体验。 -
避免全文搜索
全文搜索是Elasticsearch的核心功能,但是全文搜索会消耗大量的资源。可以尝试避免全文搜索,例如使用Filter和Aggregation等方式,以提高查询性能。 -
选择合适的节点
Elasticsearch是一个分布式系统,查询请求可能会被发送到不同的节点。可以通过选择合适的节点来提高查询性能,例如选择较快的节点或者与查询相关的节点。
Elasticsearch的缺点
Elasticsearch是一种高性能、可扩展、分布式的搜索引擎,但它也有一些缺点,包括以下几个方面:
-
存储成本较高:Elasticsearch需要大量的磁盘空间来存储索引和数据。对于小型应用程序来说,存储成本可能不是一个大问题,但对于大型应用程序来说,需要考虑存储成本和性能之间的平衡。
-
硬件要求高:Elasticsearch需要高性能的硬件来支持大量的搜索请求和索引更新。这可能需要投入一定的资金来购买高性能的硬件。
-
分布式系统的复杂性:Elasticsearch是一个分布式系统,它需要配置和管理多个节点来实现高可用性和负载均衡。这增加了系统的复杂性和维护成本。
-
内存消耗较大:Elasticsearch需要大量的内存来支持索引和搜索操作。对于大型索引和高并发负载,需要投入更多的内存来保证系统的性能。
-
数据一致性问题:Elasticsearch是一个分布式系统,数据的一致性可能会受到网络延迟和节点故障等因素的影响。这可能会导致数据不一致的问题,需要采取一些措施来保证数据的一致性。
Elasticsearch是一种强大的搜索引擎,但在实际中也存在一些缺点。在使用Elasticsearch时,需要权衡各种因素,包括性能、成本、复杂性和数据一致性等,来选择最适合自己应用场景的方案。