ElasticSearch 是一个分布式、可扩展、高性能的检索与数据分析引擎。ElasticSearch 基于 Java 编写,通过对Lucene进一步封装 ,将搜索的复杂性屏蔽起来,开发者只需要一套简单的 RESTful API 就可以操作全文检索。
1、windows环境es单节点安装
下载地址https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-9-3
下载后到指定目录解压即可,解压后的目录如下
进入bin目录,双击elasticsearch.bat启动即可。
看到started即启动成功。
默认监听的端口是9200,访问如下
浏览器安装插件,在chrome的app store中搜索Elasticsearch-head,点击安装即可。
在chrome 浏览器中,通过“扩展程序” 添加 elasticsearch head 插件的方式,这种方式无须开启 es的跨域访问,并提供了一个可操作es的图形化界面。
打开连接http://extb.cqttech.com/search/elasticsearch%2520head,点击安装,如下
访问的可视化界面如下
2、windows环境kibana安装
Kibana 是一个 Elastic 公司推出的一个针对 es 的分析及数据可视化平台,可以搜索、查看存放在 es 中的数据。
- 下载地址:https://www.elastic.co/cn/downloads/kibana
- 解压
- 配置 es 的地址信息:若 es 是默认地址以及端口,可以不用配置,具体的配置文件是config/kibana.yml
- 启动:双击kibana.bat即可
- 访问localhost:5601
界面如下
Kibana 安装好之后,首次打开时,可以选择初始化 es 提供的测试数据,也可以不使用。
3、分词器
ElasticSearch 中内置了多种分词器,如Standard Analyzer:标准分词器,适用于英语等;其中中文分词器通常使用elasticsearch-analysis-ik,这个是第三方插件,下载地址如下:https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.9.3
下载后在es的plugins目录下,新建ik目录,并将解压后的所有文件拷贝到ik目录下,重启es服务。
注:es和kibana的安装路径不能有空格,否则启动会报错。
es重启成功后,首先创建一个名为test的索引(相当于是创建一个名为test的数据库),如下
在test索引中进行分词测试,如下
4、新建文档
创建索引后,向索引中添加一个文档,如下
- _index表示文档索引
- _type表示文档类型
- _id表示文档id
- _version表示文档版本
- result表示执行的结果
- _shards表示分片信息
- _seq_no和_primary_term表示是版本控制用的
添加文档成功后,通过浏览器插件可以看到如下
5、获取文档
es中提供了GET API来查看es中的文档,如下
若获取的文档不存在,会返回如下
更新整个文档,如下
6、搜索
创建索引,如下
查询文档,如下
添加文档
查询文档
或简单查询
词项查询,根据词去查询,查询指定字段中包含给定单词的文档,如下
7、全文检索
match query 会对查询语句进行分词,分此后如果查询语句中的任何一个词项被匹配,则文档就会被索引到。
全文检索还有 match_phrase query、multi_match query、query_string query等,还有各种复杂的组合查询等,还需不断的尝试理解。
8、实例
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ldc</groupId>
<artifactId>springboot_elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_elasticsearch</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties文件
elasticsearch.host=127.0.0.1
elasticsearch.port=9200
es配置类
@Configuration
@Data
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
@Value("${elasticsearch.host}")
private String host ;
@Value("${elasticsearch.port}")
private Integer port ;
@Override
public RestHighLevelClient elasticsearchClient() {
RestClientBuilder builder = RestClient.builder(new HttpHost(host, port));
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
return restHighLevelClient;
}
}
索引库实体类
@Data
@Document(indexName = "blog_index", type = "blog")
public class EsBlog {
@Id
private int id;
/**
* 是否索引: 看该域是否能被搜索, index = true(默认为true)
* 是否分词: 表示搜索的时候是整体匹配还是单词匹配
* 是否存储: 是否在页面上显示
*/
@Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")
private String title;
@Field(type = FieldType.Text, analyzer = "ik_smart", searchAnalyzer = "ik_smart")
private String content;
public EsBlog() {
}
public EsBlog(int id, String title, String content) {
this.id = id;
this.title = title;
this.content = content;
}
}
es持久化
@Repository
public interface EsBlogRepository extends ElasticsearchRepository<EsBlog, Integer> {
/**
* 根据title或者内容分页查询
*
* @param title 标题
* @param content 内容
* @param page 分页
* @return
*/
Page<EsBlog> findByTitleOrContentLike(String title, String content, Pageable page);
}
es服务
@Service
public class EsBlogServiceImpl implements EsBlogService {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Resource
private EsBlogRepository esBlogRepository;
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Override
public void save(EsBlog blog) {
esBlogRepository.save(blog);
logger.debug("save ok");
}
@Override
public void save(List<EsBlog> blogs) {
esBlogRepository.saveAll(blogs);
logger.debug("save ok");
}
@Override
public void delete(int id) {
esBlogRepository.deleteById(id);
}
@Override
public EsBlog getById(int id) {
EsBlog esBlog = esBlogRepository.findById(id).orElse(new EsBlog());
logger.debug(esBlog.toString());
return esBlog;
}
@Override
public Page<EsBlog> getByKey(String key, Pageable pageable) {
if(StringUtils.isEmpty(key)){
return esBlogRepository.findAll(pageable);
}
return esBlogRepository.findByTitleOrContentLike(key, key, pageable);
}
@Override
public Page<EsBlog> getByKeyWord(String key, Pageable pageable) {
if(StringUtils.isEmpty(key)){
System.out.println("key is null");
}
SearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQuery("title", key))
.withQuery(matchQuery("content", key))
.withPageable(pageable)
.build();
Page<EsBlog> esBlogs = elasticsearchRestTemplate.queryForPage(searchQuery, EsBlog.class);
esBlogs.forEach(e -> logger.debug(e.toString()));
return esBlogs;
}
}
es接口
@RestController
@RequestMapping("blog")
public class EsBlogController {
@Resource
private EsBlogService searchService;
@GetMapping("init")
private String initBlog() {
List<Blog> blogs = new ArrayList<>();
blogs.add(new Blog(1, "java", "java编程语言"));
blogs.add(new Blog(2, "netty", "netty编程"));
List<EsBlog> esBlogs = new ArrayList<>();
blogs.forEach(blog -> {esBlogs.add(new EsBlog(blog.getId(), blog.getTitle(), blog.getContent()));});
searchService.save(esBlogs);
return "init Success";
}
/**
* @param blog 博客文档
* @return
*/
@PostMapping("save")
public void save(EsBlog blog) {
searchService.save(blog);
}
/**
* @param id 文档id
* @return
*/
@GetMapping("getById")
public Object getById(int id) {
return searchService.getById(id);
}
/**
* @param key 关键字
* @return
*/
@GetMapping("getByKey")
public Page<EsBlog> getByKey(HttpServletRequest request, String key) {
Pageable pageable = getPageByRequest(request);
return searchService.getByKey(key, pageable);
}
/**
* @param key 关键字
* @return
*/
@GetMapping("getByKeyWord")
public Page<EsBlog> getByKeyWord(HttpServletRequest request, String key) {
Pageable pageable = getPageByRequest(request);
return searchService.getByKeyWord(key, pageable);
}
private Pageable getPageByRequest(HttpServletRequest request) {
int page = StringUtils.isEmpty(request.getParameter("page")) ? 1 : Integer.parseInt(request.getParameter("page"));
int size = StringUtils.isEmpty(request.getParameter("size")) ? 10 : Integer.parseInt(request.getParameter("size"));
Pageable pageable = PageRequest.of(page - 1, size);
return pageable;
}
}
检索示例如下