全文检索基础
全文检索流程
流程:
创建索引:
查询索引:
相关概念
索引库
索引库就是存储索引的保存在磁盘上的一系列的文件。里面存储了建立好的索引消息以及文档对象。
** 一个索引库相当于数据库中的一张表,一个文档对象相当于数据库中的一行数据
doucument对象
获取原始内容的目的是为了索引,在索引前需要将原始内容建成文档,文档中包含一个一个的域(字段),域中存储内容。每个文档都有一个唯一的编号,就是文档id。
field对象
如果我们把document看作是数据库中的一条记录的话,field相当于是记录中的字段。field是索引库中存储数据的最小单位。field的数据类型大致可以分为数值类型和文本类型,一般需要查询的字段都是文本类型的,field还有如下属性:
是否分词:是否对域的内容进行分词处理。前提是我们对域的内容进行查询
是否索引:将Field分析后的词或整个Field值进行索引,只有索引方可搜索到
是否存储:Field值存储在文档中,存储在文档中的Field才可以从Document中获取
term对象
从文档对象中拆分出来的每个单词叫做term,不同域中拆分出来的相同的单词是不同term。term中包含两部分,一部分是文档的域名。另一部分是单词的内容。term是创建索引的关键词对象。
ElasticSearch相关概念
概述
ES是面对文档的,这意味这它可以存储整个对象或文档。然而它不仅仅是存储,还会索引每个文档的内容使之可以被搜索。在ES中,你可以对文档(而非成行成列的数据)进行索引、搜索、排序、过滤。
ES比较传统关系型数据库如下:
Relational DB -> Databases->Tables->Rows ->Columns
ES->Indices->Types->Documents->Fields
ES核心概念
索引index
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,可以定义任意多的索引。
类型type
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定,通常,会为具有一组共同字段文档定义一个类型。比如说,我们假设你运营一个博客平台
字段Field
相当于是字段表的字段,对文档数据根据不同属性进行的分类标识
映射mapping
mapping是处理数据的范式和规则方面做一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等等,这些都是映射里面可以设置的,其他就是处理es里面的数据的一些使用规则设置也叫做映射,按着最优规则处理数据对性能提高很大,因此才需要建立映射,并且需要思考如何建立映射才能对性能更好。
文档document
一个文档是一个可被索引的基础消息单元。比如,你可以拥有某一个客户的文档,某个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON格式来表示,而JSON是一个到处存在的互联网数据交互格式
在一个index/type里面,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type
接近实时NRT
ES是一个接近实时的搜索平台,这意味这,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟
集群cluster
集群就是有一个或多个节点组织在一起,它们共同持有整个数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是es。这个名字是重要的,意味一个节点只能通过指定某个集群的名字来加入这个集群
节点node
一个节点是集群的一个服务器,作为集群的一部分,它存储数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识,默认情况下,这个名字是一个随机的名字。
分片和复制 shards&replicas
一个索引可以存储超出单个节点硬件限制的大量数据。每个分片本身也是一个功能完善并且独立的索引,这个索引可以被放置到集群的任何节点上。分片很重要,主要有两方面:
1)允许你水平分割/扩展你的内容容量
2)允许你的分片(潜在地,位于多个节点上)之上进行分布式、并行的操作,进而提高性能/吞吐量
要复制的两个原因:在分片/节点失败的情况下,提高了高可用性。因为这个原因,主要到复制分片从不与原/主要分片置于同一节点上是非常重要的。扩展你的搜索量/吞吐量。因为搜索可以在所有的复制上并行运行。总之,每个索引可以被分成多个分片,一个索引也可以被复制0次或多次,一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你是不能改变分片的数量
安装
docker安装
sudo docker pull elasticsearch:5.6.8
启动
sudo docker run -id --name=zys_es -p 9200:9200 -p 9300:9300 elasticsearch:5.6.8
注意:可能因为内存不够或者进程满等原因会中断es进程
安装包安装
sudo apt-get install openjdk-8-jdk #1、安装open-jdk
#2、官网查找需要的es版本 es官网:https://www.elastic.co/cn/downloads/elasticsearch
#点击【apt-get】
#查找自己想要的版本,点击使用deb方式安装
#安装es-7.6.2
1、wgethttps://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.2-amd64.deb
2、wgethttps://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.6.2-amd64.deb.sha512
3、shasum -a 512 -c elasticsearch-7.6.2-amd64.deb.sha512
4、sudo dpkg -i elasticsearch-7.6.2-amd64.deb
#修改配置文件elasticsearch.yml
vi /etc/elasticsearch/elasticsearch.yml
{
node.name: node-1
network.host: 0.0.0.0 #允许外网访问
http.port: 9200 #指定es端口号
clauster.initial_master_nodes: ["node-1"]
}
#修改jvm.options
{
-Xms4g
-Xms4g
}
#启动es
sudo chown -R elasticsearch:elasticsearch /usr/share/elasticsearch/ #目录的owner和group改成elasticsearch
systemctl enable elasticsearch.service #设置es开机自启动
sudo systemctl start elasticsearch.service #启动es
sudo systemctl stop elasticsearch.service #停止es
#查看es运行状态
service elasticsearch status
#查看报错日志
tail -f /var/log/elasticsearch/elasticsearch.log
#检查是否运行正常
curl localhost:9200
# 开启跨域访问支持,默认为false
http.cors.enabled: true
# 跨域访问允许的域名地址
http.cors.allow-origin: "*"
# 通过为 cluster.initial_master_nodes 参数设置符合主节点条件的节点的 IP 地址来引导启动集群
cluster.initial_master_nodes: ["node-1"]
ElasticSearch的客户端操作
三种方式:
第一种:elasticsearch-head操作
第二种:使用elasticsearch提供的Restful接口直接访问
第三种:使用es提供的API直接访问
elasticsearch-head
下载elasticsearch-head安装包
进入目录下打开cmd
npm install -g grunt-cli
启动
npm install
grunt server
Postman
创建索引index和映射Mapping
注意:elasticsearch7默认不在支持指定索引类型,默认索引类型是_doc,如果想改变,则配置include_type_name: true 即可(这个没有测试,官方文档说的,无论是否可行,建议不要这么做,因为elasticsearch8后就不在提供该字段)。官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html
7.x之前:
{
"settings":{
"number_of_shards" : 3,
"number_of_replicas" : 0
},
"mappings":{
"books":{ //指定索引
"properties":{
"title":{"type":"text"},
"name":{"type":"text","index":false}, //有index
"publish_date":{"type":"date","index":false},
"price":{"type":"double"},
"number":{
"type":"object",
"dynamic":true
}
}
}
}
}
7.x之后:
{
"settings":{
"number_of_shards":3, #分片数量
"number_of_replicas":2 #每个分片副本
},
"mappings":{
//无索引
"properties":{
"id":{"type":"long"},
"name":{"type":"text","analyzer":"standard"}, //无指定index为true或为false,standard为分词器的一种,standard一个汉字一个词
"text":{"type":"text","analyzer":"ik_max_word"}
}
}
}
创建索引后设置Mapping
http://120.78.130.50:9200/blog7/hello/mapping
{
"properties":{
"id":{"type":"long"},
"name":{"type":"text","analyzer":"ik_smart"}, //无指定index为true或为false
"text":{"type":"text","analyzer":"ik_max_word"}
}
}
创建文档document
请求url:
post http://120.78.130.50:9200/blog1/_doc/1
请求体:
{
"id":1,
"name":"es是一个lucene的搜索服务器",
"text":"阿萨的贺卡收到萨拉DHL收到啦收到啦实打实的拉萨机的卡拉卡斯德拉夫拉上来就"
}
修改文档
请求url:
post http://120.78.130.50:9200/blog1/_doc/1
请求体:
{
"id":1,
"name":"es是一个lucene的搜索服务器反对犯得上",
"text":"阿萨的贺卡收到萨拉DHL收到啦收到啦实打实的拉萨机的卡拉卡斯德拉夫拉上来就"
}
文档删除document
delete http://120.78.130.50:9200/blog1/_doc/1
根据id查询文档
GET http://120.78.130.50:9200/blog1/_doc/2
结果
{
"_index": "blog1", //索引名称
"_type": "_doc", //索引类型
"_id": "2",
"_version": 1,
"_seq_no": 2,
"_primary_term": 1,
"found": true,
"_source": { //数据
"id": 1,
"name": "es是一个lucene的搜索服务器", //无指定index为true或为false
"text": "阿萨的贺卡收到萨拉DHL收到啦收到啦实打实的拉萨机的卡拉卡斯德拉夫拉上来就"
}
}
查询文档-querystring查询
url:
POST http://120.78.130.50:9200/blog1/_doc/_search
请求体:
{
"query": {
"query_string": {
"default_field": "name",
"query": "搜索服务器"
}
}
}
钢索->“钢”,“索”,搜索是分为两个词,注意Standard标准分词器,会把汉字每个字分为一个词存到索引库中的name,也就是按照Standard进行的分词,所以搜索钢索能搜到这个document
查询文档-term查询
url:
POST http://120.78.130.50:9200/blog1/_doc/_search
body
{
"query": {
"term": {
"name": "搜索"
}
}
}
query_string :搜索之前对搜索的关键词分词
term:对搜索的关键词不分词
IK分词器
安装
下载安装包 :https://github.com/medcl/elasticsearch-analysis-ik/releases
放到/ usr/share/elasticsearch/plugins
重启es
7.x之前测试:
http://120.78.130.50:9200/_analyze?analyzer=ik_smart&pretty=true&text=我是程序员
http://120.78.130.50:9200/_analyze?analyzer=ik_max_word&pretty=true&text=我是程序员
7.x之后测试:url+body
http://120.78.130.50:9200/_analyze
{
“analyzer”: “ik_smart”,
“text”: “我是傻逼”
}
注意:
ik_smart:会做最粗粒度的拆分
ik_max_word: 会将文本做最细粒度的拆分
注意出错:将ik解压成功后es可能就启动不了,可能是ik中所有文件的用户组和所有者属于root,需要改成当前的用户组和所有者,用
sudo chmod zys_ergou ./ik/*
sudo chown zys_ergou ./ik/*
还有一种情况就是es和ik的版本不兼容,需要进入plugin-descriptor.properties文件更改es的version
Kibaba
安装
第一步:去官网下载Linux版本的Kibana
https://www.elastic.co/cn/downloads/past-releases#kibana
sudo wget https://artifacts.elastic.co/downloads/kibana/kibana-7.6.2-linux-x86_64.tar.gz
第二步:上传到Linux服务器(可能导致文件不完整,最好用wget下载)
第三步:解压该Kibana压缩包。
sudo tar -zxvf kibana-7.6.2-linux-x86_64.tar.gz //注意文件名称
第四步:去kibana目录下的config/kibana.yml配置相关参数。
- server.port: 5601
- server.host: “0.0.0.0”
- i18n.locale: “zh-CN”
第五步:启动Kibana。进入bin目录下
- #root账号启动
- ./kibana --allow-root
- #root账号后台启动
- nohup ./kibana --allow-root &
- #其他账号启动
- ./kibana
- #其他账号后台启动
- nohup ./kibana &
第六步:访问Kibana
http://192.168.120.157:5601/
第七步:访问Elasticsearch地址
快捷键:
ctrl + i 自动缩进
ctrl + enter 提交请求
down 打开自动补全菜单
enter 或tab 选中项自动补全
esc 关闭补全菜单
DSL语句使用
SQL查询语句
操作
(1)查询所有索引
GET /_cat/indices?v
(2)删除某个索引
DELETE /blog
(3)新增索引
PUT /user
(4)创建映射
注意:如果不设置include_type_name=true,就会报错"Types cannot be provided in put mapping requests, unless the include_type_name parameter is set to true."
PUT /user/uesrinfo/_mapping?include_type_name=true
{
"properties": {
"name":{
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"city":{
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"age":{
"type": "long"
},
"description":{
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
}
(5)新增文档数据
PUT /user/_doc/{id}
{
"name":"王五",
"age":21,
"city":"广州",
"description":"王五来自湖北武汉"
}
(6)替换操作
PUT /user/_doc/3
{
"name":"王五",
"age":21,
"city":"广州",
"description":"王五来自湖北武汉"
}
(7)根据id查询
GET /user/_doc/2
(8)查询所有
GET /user/_search
(9)Sort排序
GET /user/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "desc"
}
}
]
}
(10)分页
GET /user/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "desc"
}
}
],
"from": 0,
"size": 2
}
(11)term查询
term主要用于分词精确匹配,如字符串、数值、日期等(不适合情况:1、列中除英文字符外有其他值2、字符串值中有冒号或中文3、系统自带属性如_version)
GET _search
{
"query": {
"term": {//term不分词
"city": "深圳武汉"
}
}
}
}
GET _search
{
"query": {
"match": {//match分词
"city": "深圳武汉"
}
}
}
(12)terms查询
terms查询允许指定多个匹配条件。如果某个字段指定了多个值,那么文档需要一起做匹配
GET _search
{
"query": {
"terms": {
"city": [
"武汉",
"广州"
]
}
}
}
(13)query_string查询
GET _search
{
"query": {
"query_string": {
"default_field": "city",
"query": "广州武汉"
}
}
}
(14)range查询
GET _search
{
"query": {
"range": {
"age": {
"gte": 20,
"lte": 22
}
}
}
}
(15)exists
exists过滤可以用于查找拥有某个域的数据
GET _search
{
"query": {
"exists": {
"field": "address"
}
}
}
(16)bool查询
bool可以用来合并多个条件查询结果的布尔逻辑,它包含以下操作符:
must:多个查询条件的完全匹配,相当于and
must_not:多个查询条件的相反匹配,相当于not
should:至少有一个查询条件匹配,相当于or
这些参数可以分别继承一个过滤条件或者一个过滤条件的数组:
GET _search
{
"query": {
"bool": {
"must": [
{
"term": {
"city": {
"value": "广州"
}
}
},
{
"range": {
"age": {
"gte": 20,
"lte": 22
}
}
}
]
}
}
}
(17)match_all查询
可以查询到所有文档,是没有查询条件下的默认句
GET /user/_search
{
"query": {
"match_all": {}
}
}
(18)match查询
match查询是一个标准查询,不管你需要全文查询还是精确查询基本上都要用到它。如果你使用match查询一个全文本字段,它会在真正查询之前用飞行器先分析match一下查询字符:
GET _search
{
"query": {
"match": {
"city": "广州"
}
}
}
(19)prefix查询
以什么字符开头的,可以更简单地用prefix,例如查询所有以张开始的用户描述
GET _search
{
"query": {
"prefix": {
"name": {
"value": "王"
}
}
}
}
(20)multi_match
multi_match查询允许你做match查询的基础上同时搜索多个字段,在多个字段中同时查一个
GET _search
{
"query": {
"multi_match": {
"query": "深圳",
"fields": [
"city",
"description"]
}
}
}
ElasticSearch编程操作
添加依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zys</groupId> <artifactId>es_demon</artifactId> <version>1.0-SNAPSHOT</version> <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>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.21</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-to-slf4j</artifactId> <version>2.9.1</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>7.6.2</version> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.6.2</version> </dependency> </dependencies> </project>
创建索引
//1、配置
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
//2、客户端
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(InetAddress.getByName("120.78.130.50"), 9300));
//3、使用api创建索引
client.admin().indices().prepareCreate("index_hello").get();
//4、关闭client
client.close();
添加映射
//1、配置
Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build();
//2、客户端
TransportClient client = new PreBuiltTransportClient(settings);
client.addTransportAddress(new TransportAddress(InetAddress.getByName("120.78.130.50"), 9300));
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder()
.startObject()
.startObject("article")
.startObject("properties")
.startObject("id")
.field("type", "long")
.endObject()
.startObject("title")
.field("type", "text")
.field("analyzer", "ik_smart")
.endObject()
.startObject("content")
.field("type", "text")
.field("analyzer", "ik_smart")
.endObject()
.endObject()
.endObject()
.endObject();
//3、使用api创建索引
client.admin().indices().preparePutMapping("index_hello").setType("article").setSource(xContentBuilder).get();
//4、关闭client
client.close();
创建文档
1、使用XContenBuilder构建Document对象
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.field("id", 2l)
.field("title", "少大金欧涉及到山东哈收到拉萨DHL撒鲁大师鲁大师劳动力")
.field("content", "啥的拉升阶段拉萨伦敦苏富比老大就是领导破碎了就爱上了大家来打死你电脑来合肥把程序内存,整理骄傲我觉得阿拉善的距离撒娇的了就")
.endObject();
client.prepareIndex()
//设置索引名称
.setIndex("index_hello")
//设置type
.setType("article")
//设置文档的id,如果不设置的话自动生成一个id
.setId("1")
//设置文档信息
.setSource(builder)
//执行操作
.get();
2、实体对象
依赖:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.1</version>
</dependency>
实体类:
private Integer id;
private String title;
private String content;
添加:
Article article = new Article();
article.setId(3l);
article.setTitle("撒娇多久啊老师的就爱上了你发到你爱丽丝的你拉车的你");
article.setContent("jdaosdnasdnlddawhlcncsnskndaskndasldnslnslkdsal;dasmd;");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(article);
client.prepareIndex()
.setIndex("index_hello")
.setType("article")
.setSource(objectMapper, XContentType.JSON)
.get();
}
查询文档
TermQuery
//创建QueryBuilder对象
// QueryBuilder queryBuilder = QueryBuilders.termQuery("title", "你");//term查询
QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery("你的宝贝").defaultField("title");//match查询
// MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "你的宝贝");//match查询
// IdsQueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds("3", "4");//根据id查询
//执行查询得到一个结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.get();
//处理结果
SearchHits hits = searchResponse.getHits();
System.out.println("总行数" + hits.getTotalHits());
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit next = iterator.next();
//文档的json输入
System.out.println(next.getSourceAsString());
}
分页查询
//创建QueryBuilder对象
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "你的宝贝");//match查询
//执行查询得到一个结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.setFrom(0)///
.setSize(5)///
.get();
//处理结果
SearchHits hits = searchResponse.getHits();
System.out.println("总行数" + hits.getTotalHits());
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit next = iterator.next();
//文档的json输入
System.out.println(next.getSourceAsString());
}
查询结果高亮显示
MultiMatchQueryBuilder queryBuilder = QueryBuilders.multiMatchQuery("少啥", "title", "content");//multi_match查询
//
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<em>");
highlightBuilder.preTags("</em>");
/
//执行查询得到一个结果
SearchResponse searchResponse = client.prepareSearch("index_hello")
.setTypes("article")
.setQuery(queryBuilder)
.highlighter(highlightBuilder)//
.get();
//处理结果
SearchHits hits = searchResponse.getHits();
System.out.println("总行数" + hits.getTotalHits());
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit next = iterator.next();
//文档的json输入
System.out.println(next.getSourceAsString());
System.out.println("==============highlight==============");
Map<String, HighlightField> highlightFieldMap = next.getHighlightFields();
for (Map.Entry<String, HighlightField> entry : highlightFieldMap.entrySet()) {
System.out.println(entry.getKey() + "\t" + Arrays.toString( entry.getValue().getFragments()));
}
}
Spring Data ElasticSearch
1、搭建spring boot项目
Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot |
---|---|---|---|---|
2022.0 (Turing) | 5.0.x | 8.5.0 | 6.0.x | 3.0.x |
2021.2 (Raj) | 4.4.x | 7.17.3 | 5.3.x | 2.7.x |
2021.1 (Q) | 4.3.x | 7.15.2 | 5.3.x | 2.6.x |
2021.0 (Pascal) | 4.2.x[1] | 7.12.0 | 5.3.x | 2.5.x |
2020.0 (Ockham)[1] | 4.1.x[1] | 7.9.3 | 5.3.2 | 2.4.x |
Neumann[1] | 4.0.x[1] | 7.6.2 | 5.2.12 | 2.3.x |
Moore[1] | 3.2.x[1] | 6.8.12 | 5.2.12 | 2.2.x |
Lovelace[1] | 3.1.x[1] | 6.2.2 | 5.1.19 | 2.1.x |
Kay[1] | 3.0.x[1] | 5.5.0 | 5.0.13 | 2.0.x |
Ingalls[1] | 2.1.x[1] | 2.4.0 | 4.3.25 | 1.5.x |
2、编写yml文件
spring:
elasticsearch:
rest:
uris: 120.78.130.50:9300
3、编写实体类
//type在2.3.x版本不写即可,实体类名字即是type
@Document(indexName = "zys_blog", type = "article")
public class Article {
@Id
@Field(type = FieldType.Long, store = true)
private Long id;
@Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
private String title;
@Field(type = FieldType.Text, store = true, analyzer = "ik_smart")
private String content;
}
4、编写Dao
方法命名规则查询的基本语法findBy+属性+关键词+连接符
关键词:and,or,is,not,between,lessThanEqual
public interface ArticleDao extends ElasticsearchRepository<Article, Long> {
}
5、使用
@Autowired
private ElasticsearchRestTemplate template ;
RestHighLevelClient
引入依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
private RestHighLevelClient client;
@Test
public void createIndex() throws IOException {
HttpHost httpHost = HttpHost.create("120.78.130.50:9200");
RestClientBuilder builder = RestClient.builder(httpHost);
client = new RestHighLevelClient(builder);
//创建连接
CreateIndexRequest request = new CreateIndexRequest("book_index");
String json = "{\n" +
" \"mappings\": {\n" +
" \"properties\": {\n" +
" \"id\":{\n" +
" \"type\":\"keyword\"\n" +
" },\n" +
" \"name\":{\n" +
" \"type\":\"text\",\n" +
" \"analyzer\":\"ik_max_word\"\n" +
" },\n" +
" \"type\":{\n" +
" \"type\":\"keyword\"\n" +
" },\n" +
" \"description\":{\n" +
" \"type\":\"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
request.source(json, XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);//创建索引库
client.close();
}
添加文档
@Test
public void addDoc() throws Exception{
Book book = bookDao.selectById(1);//从数据库中查询一个对象
IndexRequest request = new IndexRequest("book_index").id(book.getId().toString());
String json = JSON.toJSONString(book);//对象转为json
request.source(json, XContentType.JSON);
client.index(request, RequestOptions.DEFAULT);
}
//批处理添加文档//
@Test
public void addallDoc() throws Exception{
List<Book> bookList = bookDao.selectList(null);//从数据库中查询所有对象
BulkRequest bulk = new BulkRequest();//创建一个批处理对象
for (Book book : bookList) {
IndexRequest request = new IndexRequest("book_index").id(book.getId().toString());
String json = JSON.toJSONString(book);//对象转为json
request.source(json, XContentType.JSON);
bulk.add(request);
}
client.bulk(bulk, RequestOptions.DEFAULT);
}
查询文档
///根据id查询
@Test
void testQuery() throws IOException {
GetRequest request = new GetRequest("book_index","1");
GetResponse res = client.get(request, RequestOptions.DEFAULT);
String sourceAsString = res.getSourceAsString();
System.out.println(sourceAsString);
}
///条件查询/
@Test
void Query() throws IOException {
SearchRequest request = new SearchRequest("book_index");
//设置条件
SearchSourceBuilder buider = new SearchSourceBuilder();
buider.query(QueryBuilders.termQuery("name", "java"));
request.source(buider);
SearchResponse search = client.search(request, RequestOptions.DEFAULT);
//处理结果
SearchHits hits = search.getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
JSON.parseObject(sourceAsString, Book.class);//json对为对象
System.out.println(Book);
}
}
聚合查询
划分桶:把不同标题分开文章来源:https://www.toymoban.com/news/detail-605267.html
GET /car_index/car/_search
{
"query": { //查询所有
"bool": {
"should": [
{
"match_all": {}
}
]
}
},
"aggs": {
"group_by_bland": { //group_by_bland为桶名字
"terms": { //
"field": "color", //把各颜色分开,比如白色为一组(一个容器aggregations),黄色为一组
}
}
}
}
桶内度量文章来源地址https://www.toymoban.com/news/detail-605267.html
GET /car_index/car/_search
{
"query": {
"bool": {
"should": [
{
"match_all": {}
}
]
}
},
"aggs": {
"group_by_bland": {
"terms": {
"field": "color" //分开各颜色
},
"aggs": {
"avg_price": {
"avg": {
"field": "price" //求各颜色里面的价格平均值
}
}
}
}
}
}
到了这里,关于ElasticSearch搜索详细讲解与操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!