solr和ElasticSearch都是很优秀的搜索引擎。
solr对外提供类似WebService的API接口,用post方法向solr服务器发送描述field及内容的xml文档,solr根据xml文档添加、删除、更新索引。
当建索引时solr会产生IO阻塞,查询性能较差。
Lucene是一套信息检索工具包,jar包,不包含搜索引擎系统。
包含:索引结构、读写索引的工具、排序、搜索规则等等的工具类
ElasticSearch基于Lucene做了一些封装和增强,是基于倒排索引(基于value找key)的分布式全文搜索引擎,具有高可扩展性,可近乎实时搜索和存储数据。目的是通过简单的RestFul API来隐藏Lucene的复杂性。提供全文搜索、结构化搜索、分析等功能。
官网下载ElasticSearch:https://www.elastic.co/cn/downloads/elasticsearch
一、环境安装:解压即可使用,安装后的文件目录内容如下:
bin 启动文件,运行bin下elasticsearch.bat启动elasticsearch
config 配置文件
elasticsearch.yml elasticsearch的配置文件,默认9200端口
jvm.options jvm相关的配置文件
log4j2.properties 日志配置文件
roles.yml 角色配置文件
lib 相关jar包 包含lucence
logs 日志
modules 功能模块
plugins 插件,比如ik分词器
jdk 要求jdk1.8以上
安装完访问测试:http://127.0.0.1:9200/
另外需安装nodeJs、Python、Kibana(查询操作数据)、ik分词器、head处理器(可视化界面,用于展示数据)
先安装nodeJs,利用cnpm安装可视化界面 head插件,head插件GitHub下载地址:https://github.com/mobz/elasticsearch-head
cnpm install(根据package.json去淘宝镜像下载安装依赖包)
npm start (启动head)
访问测试:http://127.0.0.1:9100/
要让elasticSearch被远程启动和访问,需要修改配置config/elasticsearch.yml
跨域(跨端口、跨网站、跨ip)请求配置:
http.cors.enabled:true
http.cors.allow-origin:"*"
安装Kibana:
ELK的流程:收集清洗数据(Nginx log file、Tomcat log file)-->搜索,存储-->Kibana
Kibana可以将elasticsearch的数据通过友好的界面展示出来,提供实时分析的功能。是一个标准的工程,拆箱即用。可以通过在Kibana的可视化界面上输入命令来操作elasticsearch。
1、启动bin/kibana.bat
2、访问测试 http://127.0.0.1:5601/
3、汉化,修改kibana.yml的i18n.locale
elasticSearch是面向文档的,一切都是JSON数据。
关系型数据库 ElasticSearch
数据库(database) 索引
表(tables) types
行(rows) documents
字段(columns) fields
字段类型(mapping):fields的类型,如整形
索引是映射类型的容器。elasticsearch中的索引是一个非常大的文档集合。索引存储了映射类型的字段和其他设置。然后它们被存储到了各个分片上。
倒排索引:将value拆分,存储拆分后的value-key之间的关系,根据value找key
一般索引:根据key找对应的value
在elasticsearch中,索引被分为多个分片,每份分片是一个Lucene的索引,一个elasticsearch索引由多个Lucene索引组成。
软件包下载:https://github.com/medcl/elasticsearch-analysis-ik/
IK提供了两个分词算法:ik_smart和ik_max_word,ik_smart为最少切分,ik_max_word为最细粒度区分。
示例:
ik分词器会将存入elasticsearch的数据根据内置字典拆分出多个关键字,并存储拆分出的关键字与原始数据的关联关系,当用户输入关键字搜索时即可通过倒排索引找到对应的原始数据。
若需扩展配置自己的字典,需在ik-config中配置自己的字典,将其配置到IKAnalyzer.cfg.xml中
四、Kibanan操作命令restFul操作ES,对ES进行CRUD
创建索引:
如果自己的文档字段没有指定,es就会给我们默认配置字段类型。
在kibanna的控制台上输入命令往ES中插入文档 eg:
put /meng/type1/1
{
"name": "张三",
"age": 3,
"description": "高冷学霸,肤白貌美大长腿,Java工程师"
}
默认类型:
创建索引规则(字段类型)及字段:
put /test2
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "long"
},
"birthday": {
"type": "date"
}
}
}
}
get _cat/indices?v 获得es当前的很多信息
覆盖更新文档: 修改文档后version会+1
put /meng/type1/1
{
"name": "张三",
"age": 25
}
修改文档中指定fields:
post /meng/type1/1/_update
{
"doc":{
# 要修改的具体内容
"age": 25
}
}
删除文档:
delete /meng/type1/1五、elasticsearch查询
模糊搜索索引meng中name字段中含有Java的文档:
get /meng/type1/_search?q-name:Java
条件查询示例:
get test2/_doc/_search
{
# 模糊搜索
"query":{
"match":{
"name":"张三"
}
},
# 查询的字段
"_source": ["name","description","age"],
# 排序
"sort": [
{
"age": {
"order": "desc"
}
}
],
# 分页
"from":0,
"size":2
}
多条件匹配,多个条件都要满足(must -> and, should -> or, must_not -> not非):
get test2/_doc/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"name":"张三"
}
},
{
"match":{
"age":25
}
}
],
# 区间过滤 gt 大于, gte 大于等于, lt 小于, lte 小于等于
"filter": {
"range": {
"age": {
"gt": 21,
"lte": 25
}
}
}
}
}
}
多个条件使用空格隔开,只要满足其中一个结果就会被匹配出来,匹配出来的数据按权重排序:
get test2/_doc/_search
{
"query":{
"match":{
"tags":"男 技术"
}
}
}
精确查询和分词:
term查询直接通过倒排索引指定的词条进行精确查找。
Match 会使用分词器解析(先分析文档,然后再进行查询)
Text和keyword类型:
keyword类型不会被分词器解析。
高亮查询:
get test2/_doc/_search
{
"query":{
"match": {
"name": "java"
}
},
"highlight": {
# 自定义搜索高亮条件,前置后置标签
"pre_tags": "",
"post_tags": "
",
"fields": {
"name": {}
}
}
}
六、springBoot集成ES
1、pom中引入依赖:
org.elasticsearch.client elasticsearch-rest-high-level-client7.5.1
2、代码编写:
@Autowired RestHighLevelClient client; // 创建索引请求 CreateIndexRequest request = new CreateIndexRequest(“kuang_index”); // 客户端执行请求IndicesClient,请求后获得响应 CreateIndexResponse response = Client.indices().create(request, RequestOptions.DEFAULT);
索引相关操作:
// 获取索引 GetIndexRequest request = new GetIndexRequest (“kuang_index”); Boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); //判断是否存在 // 删除索引 DeleteIndexRequest request = new DeleteIndexRequest(“kuang_index”); AcknowledgeResponse delete= client.indices().delete(request, RequestOptions.DEFAULT); delete.isAcknowledged();
文档CRUD:
// 创建文档 User user = new User(“法外狂徒张三”, 3); IndexRequest request = new IndexRequest(“kuang_index”); // 规则:put /kuang_index/_doc/1 request.id(“1”); // 设置请求超时时间 request.timout(“1ms”); //将数据放入请求 request.source(JSON.toJsonString(user), XContentType.JSON); //客户端发送请求,获取响应的结果 IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT); indexResponse.status(); // 对应命令返回的状态,created、updated // 获取文档 GetRequest request = new GetRequest(“kuang_index”, “1”); request.fetchSourceContext(new FetchSourceContext(false)); request.storedFields(“_none_”); // 判断文档是否存在 boolean exists = client.exists(request, RequestOptions.DEFAULT); GetResponse response = client.get(request, RequestOptions.DEFAULT); response.getSourceAsString(); //文档内容 // 更新文档 UpdateRequest updRequest = new UpdateRequest(“kuang_index”, “1”); updRequest.timout(“1ms”); User user = new User(“法外狂徒张三”, 18); updRequest.doc(JSON.toJsonString(user), XContentType.JSON); UpdateResponse updResponse = client.update(updRequest, RequestOptions.DEFAULT); updResponse.status(); // 更新状态 // 删除文档 DeleteRequest delRequest = new DeleteRequest(“kuang_index”, “1”); delRequest.timout(“1ms”); DeleteResponse delResponse = client.delete(delRequest, RequestOptions.DEFAULT); delResponse.status(); // 批量插入,批处理请求 BulkRequset bulkRequest = new BulkRequest(); bulkRequest.timout(“10s”); ArrayListuserList = new ArrayList<>(); userList.add(new User(“法外狂徒张三java”, 3)); userList.add(new User(“法外狂徒张三python”, 4)); userList.add(new User(“法外狂徒张三前端”, 5)); for(int i = 0;i< userList.size(); i++){ bulkRequest.add(new IndexRequest("kuang_index").id(""+(i+1)).source(JSON.toJsonString(userList.get(i)), XContentType.JSON)); } BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT); bulkResponse.hasFailures(); // 执行是否失败 // 查询请求 SearchRequest searchRequest = new SearchRequest(“kuang_index”); // 构造搜索条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 模糊匹配,精确匹配用TermQueryBuilder // 查询条件,使用QueryBuilders工具来实现 MatchAllQueryBuilder queryBuilder = QueryBuilders.matchAllQuery(“name”, “狂神”); sourceBuilder.query(queryBuilder); queryBuilder.timeout(new Timevalue(60, TimeUnit.SECONDS)); // 分页条件 sourceBuilder.from(1); sourceBuilder.size(20); searchRequest.source(sourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 查询的返回值 searchResponse.getHits(); for(SearchHit documents: searchResponse.getHits().getHits()){ System.out.println(documents.getSourceAsMap()); } // 高亮搜索 HighLightBuilder



