全文搜索引擎的概念
全文搜索引擎是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
常见的全文搜索引擎及对比
①Lucene
Lucene是一个Java全文搜索引擎,完全用Java编写。Lucene不是一个完整的应用程序,而是一个代码库和API,可以很容易地用于向应用程序添加搜索功能
优点:比较成熟的解决方案,具有活跃的社区,经过优化,可以支持10亿+的搜索
缺点:所有的扩展,分布式,可靠性等都需要自己实现;非实时,从建索引到可以搜索中间有一个时间延迟。
②solar
Solr是一个基于名为Lucene的Java库构建的开源搜索平台。它以用户友好的方式提供Apache Lucene的搜索功能。作为一个行业参与者近十年,它是一个成熟的产品,拥有强大而广泛的用户社区。它提供分布式索引,复制,负载平衡查询以及自动故障转移和恢复。如果它被正确部署然后管理得好,它就能够成为一个高度可靠,可扩展且容错的搜索引擎
优点:Solr有一个更大、更成熟的用户、开发和贡献者社区;支持多种文件的索引,如JSON,XML,CSV,PDF,HTML,WORD;不考虑建立索引,搜索速度更快。
缺点:建立索引耗时较长,实时搜索的效率不高
③Elasticsearch
Elasticsearch(elastic)是一个基于Apache Lucene库构建的RESTful搜索引擎,它提供了一个分布式,多租户能力的全文搜索引擎,具有HTTP Web界面(REST)和无架构JSON文档。分布式搜索引擎包括可以划分为分片的索引,并且每个分片可以具有多个副本。每个Elasticsearch节点都可以有一个或多个分片,其引擎也可以充当协调器,将操作委派给正确的分片。
优点:Elasticsearch是分布式的,可以实时分发;支持Lucene接近实时的搜索;处理多租户(multienancy)不需要特殊的配置,而slor则需要更多高级的配置
缺点:社区没有solar那么活跃;由于发布出来时间较短,较solar不稳定;不够自动,不适应当前新的index warmup API(索引预热)
Elasticsearch基本概念
①Index:索引,Elastic 数据管理的顶层单位,写入数据后经处理会生成倒排索引(Inverted Index)
②Document:文档,Index里面的单条数据记录
③Type:Document可以进行分组,Type就是这种分组,使用Type可以对Document进行过滤
④Cluster:集群,Elastic是一个分布式数据库,众多的节点组成了一个集群
⑤Node:单个elastic实例为一个节点,节点分为主节点跟分节点。当一个节点被选举成为主节点时,它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等,任何节点都有可能被选举成主节点
⑥分片:数据的容器,分为主分片跟副分片。一个主分片理论上可以存储Integer.MAX_VALUE - 128 个文档,索引建立时已经确定了主分片的数量。副分片作为主分片的拷贝,作为硬件故障时保护数据不丢失的冗余备份。分片可以分布在同一节点,但是为了做到数据备份跟负载均衡,一般会将不同分片分布在不同的节点上。
全文搜索引擎基本原理-倒排索引
当往Elasticsearch插入数据时,会建立对应的文档来存储数据,并且根据分词规则对数据进行拆分,然后建立不同的词条跟所在文档的倒排索引。当进行搜索时,会对搜索关键字进行拆分,并且匹配倒排索引中维护的词条,最终查找出对应的文档。
如现在存在两个文档,每个文档中的content包括以下内容:
1.本文作者是吃雪糕也放辣椒
2.读完本文给作者点个赞
然后根据分词规则将文本拆分成词条,并且建立倒排索引,如下所示:
当输入“读完本文”关键字时,会匹配到以下结果:
从上面匹配结果来看,文档2的匹配度更加高。如果我们使用仅计算匹配词条数量的简单 相似性算法 ,那么,我们可以说,对于我们查询的相关性来讲,第二个文档比第一个文档更佳。
Elastic的简单使用
①环境的搭建
1.安装1.8版本及以上JDK
2.安装elastic,直接上官网下载解压即可,下载链接>https://www.elastic.co/cn/downloads/elasticsearch
解压完后,cd /安装目录/elasticsearch-6.5.4/bin
运行 elasticsearch.bat,可以看到elastic已经以9300的端口启动:
http端口可以在 /安装目录/elasticsearch-6.5.4/config/elasticsearch.yml中进行修改
3.安装IK分词器,下载链接>https://github.com/medcl/elasticsearch-analysis-ik/releases
解压在 /安装目录/elasticsearch-6.5.4/plugins即可
4.安装可视化界面kibana,下载链接>https://www.elastic.co/cn/downloads/kibana
下载完后直接解压即可,cd /安装目录/kibana-6.5.4-windows-x86_64/config,在kibana.yml可以设置elastic的ip及端口:
然后cd /安装目录/kibana-6.5.4-windows-x86_64/bi,进入kibana.bat启动
②SpringBoot整合Elasticsearch
1.导入elastic依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
2.配置节点
#application.properties
# 配置集群名称,名称写错会连不上服务器,默认elasticsearch
spring.data.elasticsearch.cluster-name=elasticsearch
# 配置集群节点
spring.data.elasticsearch.cluster-nodes=localhost:9300
#是否开启本地存储
spring.data.elasticsearch.repositories.enabled=true
3.建立模型Demo
@Data
@Document(indexName="shop")
public class Product {
@Id
private String id;
/**
* searchAnalyzer:分词器
* type:字段类型
* fielddata:预加载
*/
@Field(analyzer="ik_smart",searchAnalyzer="ik_smart",type = FieldType.Text,fielddata = true)
private String title;
private Integer price;
@Field(analyzer="ik_smart",searchAnalyzer="ik_smart",type = FieldType.Text,fielddata = true)
private String intro;
@Field(type= FieldType.Keyword)
private String brand;
}
4.创建Repository
public interface EsRepository extends ElasticsearchRepository<Product, String> {
}
5.创建业务接口
/**
* @author wangsj
*/
public interface EsProduct {
/**
* 添加数据
* @param product 商品对象
* @return 返回添加的商品对象
*/
Product create(Product product);
/**
* 魔魂查询
* @param keyword 名字
* @return 商品集合
*/
List<Product> search(String keyword);
/**
* 高亮查询
* @param keyword 搜索关键字
* @return AggregatedPage
*/
AggregatedPage<Product> highLightSearch(String keyword);
}
6.业务接口实现类
public class EsProductImpl implements EsProduct {
@Autowired
private EsRepository esRepository;
@Autowired
private ElasticsearchTemplate template;
@Override
public Product create(Product product) {
Product pro = esRepository.save(product);
return pro;
}
@Override
public List<Product> search(String keyword) {
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
builder.withQuery(
QueryBuilders.multiMatchQuery(keyword, "title", "intro")
);
builder.withPageable(PageRequest.of(0, 100, Sort.Direction.DESC, "brand"));
Page<Product> search = esRepository.search(builder.build());
List<Product> pros = search.getContent();
return pros;
}
@Override
public AggregatedPage<Product> highLightSearch(String keyword) {
// Java与JSON互转的工具对象
ObjectMapper mapper = new ObjectMapper();
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
// 设置查询哪个索引中的哪个类型
builder.withIndices("shop");
builder.withQuery(
QueryBuilders.multiMatchQuery(keyword,
"title", "intro")
);
builder.withHighlightFields(
new HighlightBuilder.Field("title")
.preTags("<span style='color:red'>").postTags("</span>"),
new HighlightBuilder.Field("intro")
.preTags("<span style='color:red'>").postTags("</span>")
);
AggregatedPage<Product> page = template.queryForPage(builder.build(), Product.class,
new SearchResultMapper(){
@Override
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
List<T> list = new ArrayList<>();
for (SearchHit hit : response.getHits().getHits()) {
list.add(mapSearchHit(hit, clazz));
}
long total = response.getHits().totalHits;
return new AggregatedPageImpl<>(list, pageable, total);
}
@Override
public <T> T mapSearchHit(SearchHit searchHit, Class<T> type) {
T t = null;
try {
t = mapper.readValue(searchHit.getSourceAsString(), type);
for (HighlightField field : searchHit.getHighlightFields().values()) {
// 替换需要高亮显示的字段,用到Apache的BeanUtils工具
BeanUtils.setProperty(t, field.getName(), field.getFragments()[0].string());
}
}catch (Exception e){
e.printStackTrace();
return null;
}
return t;
}
});
return page;
}
}
7.实例测试
(1)新增数据
@Test
public void testCreate(){
Product product = new Product();
product.setBrand("三星");
product.setIntro("性价比不高的手机");
product.setTitle("贵手机");
product.setId("3");
esProduct.create(product);
}
打开kibana,可以看到elastic中已经新建立了一条数据
(2)模糊查询
@Test
public void testSearch(){
List<Product> pros = esProduct.search("甩");
System.out.println(pros);
}
输入搜索关键字为“甩”,运行结果:
(3)高亮查询
@Test
public void testHighLightSearch(){
AggregatedPage<Product> page = esProduct.highLightSearch("甩");
page.forEach(System.out::println);
}
输入搜索关键字为“甩”,运行结果:
在页面直观的效果类似于往百度输入搜索关键字,然后返回结果会将关键字渲染成红色
③Elasticsearch进阶
elastic可以进行复杂的聚合运算,如桶聚合,还可以进行统计、排序、分页等等,进一步学习可以参考官方文档:>https://www.elastic.co/guide/en/elasticsearch/reference/6.0/search-aggregations.html