一.全文搜索概述
1.1.什么是全文检索
百度百科解释:
全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。全文搜索搜索引擎数据库中的数据
说简单点:其实就是从文本中进行一个关键字的搜索
1.2.常见的全文搜索
Lucene:
Lucene是apache下的一个开源的全文检索引擎工具包(一堆jar包)。它为软件开发人员提供一个简单易用的工具包(类库),以方便的在小型目标系统中实现全文检索的功能。
Elastic Search(ES):
ES是一个分布式的全文搜索引擎,为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案,ES的索引库管理支持依然是基于Apache Lucene™的开源搜索引擎。
Elastic的工作原理:
一是创建索引:
创建索引 : 就是把采集来的数据存储到ES索引库的过程
二是搜索索引:
搜索索引:搜索创建的索引,然后返回结果的过程
倒排索引
创建流程: 将所有的数据单词通过空格进行分词,中文通过中文分词器的规则分词,分词之后进行排序,相同的单词进行合并 既单词在前,后面挂载上他的文档编号
如何搜索:首先去搜索倒排文档前面的单词,因为是有序的,所以搜索效率高 ,搜索到单词后通过单词后面的编号直接就可以取到数据返回
ES下载和安装
下载ElasticSearch
下载地址:https://www.elastic.co/downloads/elasticsearch
解压即可,双击安装目录 bin/elasticsearch.bat即可启动
提示:以下是本篇文章正文内容,下面案例可供参考
ElasticSearch测试
使用浏览器访问:http://localhost:9200
ES内存配置
如果ES启动占用的内存比较大可以通过修改 jvm.options 文件来修改内存
Kibana安装
下载Kibana安装与启动
下载地址:https://www.elastic.co/downloads/kibana
解压即可安装 , 执行bin\kibana.bat 即可启动Kibana
Kinbana连接ES配置
解压并编辑config/kibana.yml,设置elasticsearch.url的值为已启动的ES
测试Kibana
浏览器访问 http://localhost:5601 Kibana默认地址
ElasticSearch基础
基本概念
Index:索引库 —既可以理解为sql中的库
Type:类型 —既可以理解为sql中的表
Document&field —既可以理解为sql中的字段(行和列)
文档的CRUD
添加文档
PUT /index/type/id {json}
获取文档
GET /index/type/id
修改文档
同添加:ID存在,就是修改 : 全量
局部修改:
POST /index/type/id/_update
{
"doc":{
要改的字段
}
}
字符串查询
GET /index/type/_search?q=key:value&key:value
DSL查询
1.什么是DSL查询
DSL查询是由ES提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。
`关键字查询:放到DSL查询(相关性排序)
2.DSL查询语法
GET /crm/user/_search
{
"query":{
"match":{
"username":"hello java"
}
}
}
DSL过滤
1.什么是DSL过滤
DSL过滤语句和DSL查询语句非常相似,但是它们的使用目的却不同。通常我们把DSL查询和DSL过滤一起用,当我们把查询条件放到DSL查询语句中,那么对应的字段就会进行相关性排序(ES底层维护了一个分数,用来排序),如果是把查询条件放到DSL过滤语句中,则不会进行相关性排序,因此性能更高。
等值匹配的条件:DSL过滤
DSL查询+过滤语法 如下:
GET /crm/user/_search
{
"query": {
"bool": { // 组合查询
"must": [{ //与(must) 或(should) 非(must not)
"match": { //match : 标准查询,会对查询的内容分词后去查询
"username": "hello world" //等同于:where username=hello or username=world
},
}],
"filter": { //过滤语句,写法和must一样
"term": { //次元查询,把查询的内容当成一个整体去查询
"name": "hello world" //等同于 where name = "hello world"
}
}
}
},
"from": 20,
"size": 10,
"_source": ["name", "age", "username"],
"sort": [{
"join_date": "desc"
}, {
"age": "asc"
}]
}
查询方式
bool:组合 match:分词 term:不分词 prefix:前缀 range:范围 wildcard:通配符
文档映射
1.什么是文档映射
ES的文档映射(mapping)机制用于进行字段类型确认,将每个字段匹配为一种确定的数据类型。就如同Mysql创建表时候指定的每个column列的类型。 为了方便字段的检索,我们会指定存储在ES中的字段是否进行分词,但是有些字段类型可以分词,有些字段类型不可以分词,所以对于字段的类型需要我们自己去指定。
需要记忆的:
字符串 是在数据指定的时候确定
text :分词
keyword :不分词
其他类型:和java差不多
文档映射案例
单类型创建映射:
put aigou/goods/_mapping
{
"goods": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
}
}
SpringBoot整合ES
1.导入依赖
<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-test</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
2.配置yml
spring:
elasticsearch:
rest:
uris: http://localhost:9200
3.定义DOC对象
@Document(indexName = "order",type = "_doc")
@Data
public class OrderDoc {
@Id
private Long id;
@Field(type = FieldType.Text,analyzer = "ik_smart", searchAnalyzer = "ik_smart")
private String title;
@Field(type = FieldType.Keyword)
private String color;
@Field(type = FieldType.Integer)
private int state;
@Field(type = FieldType.Double)
private BigDecimal money;
@Field(type = FieldType.Date)
private Date createTime;
}
4.初始化索引库和文档映射
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ESApp.class)
public class ESTest {
@Autowired
private ElasticsearchRestTemplate template;
@Test
public void Test() {
boolean index = template.createIndex(OrderDoc.class);
System.out.println(index);
boolean mapping = template.putMapping(OrderDoc.class);
System.out.println(mapping);
OrderDoc OrderDoc = new OrderDoc();
OrderDoc.setColor("红色");
OrderDoc.setId(1L);
OrderDoc.setTitle("水电费是的");
OrderDoc.setState(1);
OrderDoc.setMoney(new BigDecimal(999));
OrderDoc.setCreateTime(new Date());
OrderDoc save = orderDocRepository.save(OrderDoc); //添加 返回值为添加值
Iterable<OrderDoc> all = orderDocRepository.findAll(); //看不见???
System.out.println(all);
orderDocRepository.deleteById(3L); //根据id删除
}
}
5.定义Repository
@Service
public interface OrderDocRepository extends ElasticsearchRepository<OrderDoc,Long> {
}
ES的CRUD
1.添加
courseElasticsearchRepository.save(doc)
2.删除
courseElasticsearchRepository.deleteById(1L);
3.获取
Optional optional = courseElasticsearchRepository.findById(1L);
CourseDoc courseDoc = optional.get();
4.高级查询
//需求:查询课程名 name 中包含 java : DSL查询 - must - match
// 价格 price 在 1000 - 3000 : DSL过滤 - filter - range
// 每页 10 条,取第一页 ,按照价格倒排
@Test
public void testSearch(){
//创建一个本机查询builder
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//=================================================
//1.查询条件
//组合查询
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//查询课程名 name 中包含 java : DSL查询 - must - match
boolQueryBuilder.must(QueryBuilders.matchQuery(“name”,“php”));
//价格 price 在 1000 - 3000 : DSL过滤 - filter - range
boolQueryBuilder.filter(QueryBuilders.rangeQuery(“price”).gte(1000).lte(3000));
builder.withQuery(boolQueryBuilder);
//2.排序 按照价格倒排
builder.withSort(new FieldSortBuilder(“price”).order(SortOrder.DESC));
//3.分页
builder.withPageable(PageRequest.of(0,10));
//=================================================
//构建一个查询对象
NativeSearchQuery searchQuery = builder.build();
//执行查询,得到结果
Page page = courseElasticsearchRepository.search(searchQuery);
//page -> PageList
System.out.println(“总条数:”+page.getTotalElements());
System.out.println(“总页数:”+page.getTotalPages());
//结果列表
List content = page.getContent();
content.forEach(courseDoc -> {
System.out.println(courseDoc);
});
}