什么是ElasticSearch?
什么是全文检索?
计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式
全文检索? ==> 全部都搜索 ==> 如何实现全部都搜索? ==> 分词 单词永不重复 单词就是索引 单词是最小的搜索单位
要了解ElasticSearch,首先要了解以下几个概念
- 索引:存储数据的表结构 ,任何搜索数据,存放在索引对象上,用关系型数据库来表示就可以表示成数据库的一个表。
- 映射:即数据(文档)如何存储在索引对象上,存储的数据类型、是否存储、是否分词 …
- 文档:一条数据记录, 存在索引对象上,用关系型数据库来表示则可以表示为表中的一条记录。
- 文档类型:一个索引对象 存放多种类型数据, 数据用文档类型进行标识。
总结:在编程时,建立索引对象 — 建立映射 — 存储数据【文档】 — 指定文档类型进行搜索数据【文档】
为什么要使用ElasticSearch?
字段模糊查询,涉及大数据属性问题 like模糊查询无法对数据列应用索引 只能一条条字符串比对查询,效率非常低下,因此产生一种解决方案:建立数据索引库,采用全文检索的方式进行 全文索引可以将文本进行切分,建立成一个个词条的索引,最后进行检索的优化(检索文本中的每个词与搜索项进行比对)
ElasticSearch的下载与插件的安装
下载链接官网
下载完成后的目录结构:
bin 存放 elasticSearch 运行命令
config 存放配置文件
lib 存放 elasticSearch 运行依赖 jar 包
modules 存放 elasticSearch 模块
plugins 存放插件
运行 elasticSearch/bin/elasticsearch.bat 文件
注意运行处理文件之前需要有Java_Home的环境
安装插件:需要安装两个插件: head与ik分词器
运行%elasticsearch%/bin/plugin.bat install mobz/elasticsearch-head命令
访问 http://localhost:9200/_plugin/head/
Ik分词器与ElasticSearch的集成
为什么要使用IK分词器
因为IK分词器使用最细粒度切分算法,采用智能分词,ElasticSearch默认的分词器会将字符切分成单个词条,不利于检索。
1、 下载开源项目
下载链接官网
2、 打包 ik 分词器
mvn clean 清空
mvn package 打包
3、 进入 target/release 目录
将下列文件 ,拷贝到 %es%/plugins/analysis-ik
4、 进入 target/release/config 目录
将所有配置文件,复制 %es%/config 下
5、 配置 elasticsearch.yml
6、 重启 es
发现 ik 分词器被加载
7、访问
http://localhost:9200/_analyze?analyzer=ik&pretty=true&text=我爱你中国
ElasticSearch的使用
- 首先导入ElasticSeach的Maven依赖包
<!-- elasricSearch的依赖包 -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- jackson的核心包 elasticSearch本身集成了jackson -->
<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>
- 建立文档,自动创建索引
@Test
//直接在ElasticSearch中建立文档,自动创建索引
public void demo1() throws Exception{
//创建连接搜索服务器对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//描述json数据
/**
* {id:xxx,title:xxx,content:xxxx}
*/
XContentBuilder builder = XContentFactory.jsonBuilder().startObject()
.field("id",1)
.field("title","ElasticSearch是一个基于Lucene的搜索服务器")
.field("contend","它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。")
.endObject();
//建立文档对象
client.prepareIndex("blog1", "article", "1").setSource(builder).get();
//关闭搜索服务器操作
client.close();
}
- 搜索创建的文档对象
//搜索在ElasticSerach中创建的文档对象
@Test
public void demo2()throws Exception{
//简历client对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//搜索数据
//boolQuery 布尔查询。可以用来组合多个查询条件
//fuzzyQuery相似度查询
//matchQuery查询所有数据
//regexQuery正则表达式查询
//termquery 词条查询
//这里的get相当于exectue.actionGet();
//得到查询响应对象
SearchResponse searchResponse = client.prepareSearch("blog1").setTypes("article").setQuery(QueryBuilders.matchAllQuery()).get();
//获取命中次数,查询结果有多少对象
printResult(searchResponse);
//关闭连接
client.close();
}
- 查询的各种使用
@Test
//各种查询的使用
public void demo3()throws Exception{
//简历client对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//进行分词查询
//SearchResponse searchResponse = client.prepareSearch("blog1").setTypes("article").setQuery(QueryBuilders.queryStringQuery("全面")).get();
//默认的分词器是将内容一个词一个词的划分,因此模糊查询不到
//进行词条查询
//SearchResponse searchResponse = client.prepareSearch("blog1").setTypes("article").setQuery(QueryBuilders.wildcardQuery("contend", "*全文*")).get();
//进行词条查询
SearchResponse searchResponse = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.termQuery("content", "搜索")).get();
//获取命中次数,查询结果有多少对象
printResult(searchResponse);
//关闭连接
client.close();
}
- 创建索引
@Test
//索引操作
public void demo4()throws Exception{
//简历client对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//创建索引
client.admin().indices().prepareCreate("blog2").get();
//删除索引
//client.admin().indices().prepareDelete("blog2").get();
client.close();
}
- 创建映射,根据IK分词器进行分词
@Test
//映射操作 创建映射
public void demo5()throws Exception{
//简历client对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//添加映射
XContentBuilder builder = XContentFactory.jsonBuilder().startObject().startObject("article").startObject("properties")
.startObject("id").field("type","integer").field("store","yes").endObject()
.startObject("title").field("type","string").field("store","yes").field("analyzer","ik").endObject()
.startObject("content").field("type","string").field("store","yes").field("analyzer","ik").endObject()
.endObject().endObject().endObject();
PutMappingRequest mapping = Requests.putMappingRequest("blog2").type("article").source(builder);
client.admin().indices().putMapping(mapping).get();
client.close();
}
- 对已经存在的数据转换成json进行文档的添加
@Test
//对已经存在的数据转化成json数据进行增加文档
public void demo6() throws Exception{
//创建连接搜索服务器对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
//描述json数据
/**
* {id:xxx,title:xxx,content:xxxx}
*/
Atricle article = new Atricle();
article.setId(2);
article.setTitle("搜索工作的创建其实很快乐");
article.setContent("我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。");
ObjectMapper objectMapper = new ObjectMapper();
//基于jackson将数据传入到es 建立文档
//client.prepareIndex("blog2","article",article.getId().toString()).setSource(objectMapper.writeValueAsString(article)).get();
//修改文档 修改一
//client.prepareUpdate("blog2", "article", article.getId().toString()).setDoc(objectMapper.writeValueAsString(article)).get();
//修改文档 修改二
//client.update(new UpdateRequest("blog2","article",article.getId().toString()).doc(objectMapper.writeValueAsString(article))).get();
//删除文档 方法一
//client.prepareDelete("blog2", "article", article.getId().toString()).get();
//删除文档 方法二
client.delete(new DeleteRequest("blog2", "article", article.getId().toString())).get();
//关闭搜索服务器操作
client.close();
}
- ElasticSearch的分页查询
//搜索在ElasticSerach中创建的文档对象 分页查询
@Test
public void demo8()throws Exception{
//简历client对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.matchAllQuery());
//在get之前设置哪里开始查询,设置查询多少条数据
SearchResponse searchResponse = searchRequestBuilder.setFrom(5).setSize(5).get();
//获取命中次数,查询结果有多少对象
printResult(searchResponse);
//关闭连接
client.close();
}
- 高亮查询结果处理
@Test
public void demo9()throws Exception{
//简历client对象
Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));
ObjectMapper objectMapper = new ObjectMapper();
SearchRequestBuilder searchRequestBuilder = client.prepareSearch("blog2").setTypes("article").setQuery(QueryBuilders.termQuery("content", "搜索"));
//高亮定义
//需要对哪个字段进行高亮
searchRequestBuilder.addHighlightedField("content");
//前置元素
searchRequestBuilder.setHighlighterPreTags("<em>");
//后置元素
searchRequestBuilder.setHighlighterPostTags("</em>");
//在get之前设置哪里开始查询,设置查询多少条数据
SearchResponse searchResponse = searchRequestBuilder.get();
//获取命中次数,查询结果有多少对象
SearchHits hits = searchResponse.getHits();
//获得查询结果
System.out.println("查询结果有:" +hits.getTotalHits()+"条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
//每个查询对象
SearchHit searchHit = iterator.next();
//将高亮处理后内容,替换原有内容(原有内容,可能会出现显示不全)
//获取高亮显示域
Map<String, HighlightField> fields = searchHit.getHighlightFields();
//获取title的高亮显示
HighlightField titleField = fields.get("content");
//获取到原有内容中 每个高亮显示集中位置,高亮片段
Text[] fragments = titleField.fragments();
String title = "";
for (Text text : fragments) {
title +=text;
}
//将json数据转成Articlt对象
Atricle atricle = objectMapper.readValue(searchHit.getSourceAsString(),Atricle.class);
//用高亮后的内容,替换原有内容
atricle.setContent(title);
//获取字符串格式打印
System.out.println(atricle);
}
//关闭连接
client.close();
}
- 封装查询结果
//抽取查询结果封装
private void printResult(SearchResponse searchResponse) {
SearchHits hits = searchResponse.getHits();
//获得查询结果
System.out.println("查询结果有:" +hits.getTotalHits()+"条");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
//每个查询对象
SearchHit searchHit = iterator.next();
//获取字符串格式打印
System.out.println(searchHit.getSourceAsString());
System.out.println("title"+searchHit.getSource().get("title"));
}
}