环境说明
操作系统:windows10
安装、配置
ElasticSearch
第一步:下载
下载:官网下载地址
第二步:解压运行
解压zip 并进入bin目录下 双击elasticsearch.bat 运行
第三步:查看是否运行成功
访问 http://localhost:9200/
出现该界面说明运行成功
无需其他配置 其余可以在springboot集成时进行相应操作
第四步:ik分词器
下载对应版本的ik分词器包后 在es安装目录\plugins下新建ik文件夹 将下载好的ik zip包解压到该目录下
分词效果 其中 ik_smart 为最少切分,ik_max_word为最细粒度划分
ik_smart : 将一个中文字符串进行最少的单词切分:
ik_max_word : 将一个中文字符串进行尽可能多的单词切分:
第五步:创建索引并指定默认分词
{"settings":{"index":{"analysis.analyzer.default.type":"ik_max_word"}}}
Solr
第一步:下载
第二步:解压运行
解压后运行cmd进入bin目录执行 solr start命令 (solr restart -p 8983重启命令)
第三步:查看是否运行成功
浏览器进入 http://localhost:8983/solr
第四步:创建core(可以理解为数据库)
solr create -c “core名称”
第五步:注册字段
进入G:\solr\solr-8.9.0\server\solr\demo-core\conf
demo-core 为创建的core名称
进行字段配置
<field name="cityCode" type="string" indexed="true" stored="true"/>
<field name="code" type="string" indexed="true" stored="true"/>
<field name="firstChar" type="string" indexed="true" stored="true"/>
<field name="jianPin" type="string" indexed="true" stored="true"/>
...
第六步:配置IK分词器
将下载好的jar包放入\server\solr-webapp\webapp\WEB-INF\lib 下
然后配置managed-schema中添加ik分词器的配置(\server\solr\demo-core\conf)
<fieldType name="ik_word" class="solr.TextField">
<analyzer type="index">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" conf="ik.conf"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
将字段配置中的type改为 ik_word
<field name="cityCode" type="string" indexed="true" stored="true"/>
<field name="code" type="string" indexed="true" stored="true"/>
<field name="firstChar" type="string" indexed="true" stored="true"/>
<field name="jianPin" type="string" indexed="true" stored="true"/>
<field name="mergerName" type="ik_word" />
...
测试
springboot 集成
ElasticSearch
第一步:引入maven包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.5.4</version>
</dependency>
第二步:配置客户端对象
@Configuration
public class ElasticSearchConfig {
@Bean
public RestHighLevelClient restHighLevelClient() {
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
return client;
}
}
第三步:使用客户对象进行操作
package com.southsmart.demo.elasticsearch.controller;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.southsmart.demo.elasticsearch.config.ElasticSearchConfig;
import com.southsmart.demo.elasticsearch.mapper.CityMapper;
import com.southsmart.demo.elasticsearch.model.dto.CityDTO;
import com.southsmart.demo.elasticsearch.model.po.CityPO;
import com.southsmart.web.common.result.Result;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* @author clm
* @version 1.0
* @since 2021/9/8
*/
@RestController
@RequestMapping("cityEs")
@RequiredArgsConstructor
public class CityEsController {
@Autowired
private RestHighLevelClient restHighLevelClient;
@Autowired
private CityMapper cityMapper;
/**
* 添加数据
* @param indexName
* @return
* @throws IOException
*/
@GetMapping("addCityData/{indexName}")
public Result addCityData(@PathVariable String indexName) throws IOException {
List<CityPO> cityList= cityMapper.selectList(new LambdaQueryWrapper<>());
BulkRequest bulkRequest=new BulkRequest();
bulkRequest.timeout(TimeValue.timeValueSeconds(10));
for (int i = 0; i < cityList.size(); i++) {
CityDTO dto= BeanUtil.copyProperties(cityList.get(i),CityDTO.class);
//批量更新和批量删除在这里修改对应的请求即可
bulkRequest.add(new IndexRequest(indexName)
.id(dto.getId()+"")
.source(JSONUtil.toJsonStr(dto),XContentType.JSON));
}
BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
return Result.ok("插入成功");
}
/**
* 查询
* @param indexName
* @param name
* @param filedName
* @param size
* @return
* @throws IOException
*/
@GetMapping("search")
public Result search(@RequestParam String indexName, @RequestParam String name, @RequestParam String filedName, @RequestParam Integer size) throws IOException {
SearchRequest searchRequest = new SearchRequest(indexName);
//构建搜索的条件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//QueryBuilders.termQuery() 精确匹配
MultiMatchQueryBuilder termQueryBuilder = QueryBuilders.multiMatchQuery(name,filedName);
//QueryBuilders.matchAllQuery();
TermQueryBuilder termQueryBuilder1=QueryBuilders.termQuery(filedName,name);
sourceBuilder.query(termQueryBuilder1);
//分页 默认有 可以不写
sourceBuilder.from(0);
sourceBuilder.size(size);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//构建搜索
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
List<Map<String, Object>> resultList=new ArrayList<>();
for (SearchHit documentFields : searchResponse.getHits().getHits()) {
resultList.add(documentFields.getSourceAsMap());
}
return Result.ok(resultList);
}
}
Solr
第一步:引入maven包
因为maven仓库里面没有该jar包 从外部引用(在工程目录创建lib,将jar包放入其中)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
<version>2.4.9</version>
<systemPath>${project.basedir}/lib/spring-boot-starter-data-solr-2.4.9.jar</systemPath>
</dependency>
第二步:配置客户端
在application.properties中配置solr地址
spring.data.solr.host=http://localhost:8983/solr/demo-core
然后在项目中直接引入即可
@Autowired
private SolrClient solrClient;
第三步:使用客户对象进行操作
package com.southsmart.demo.solr.controller;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.southsmart.demo.solr.mapper.CityMapper;
import com.southsmart.demo.solr.model.dto.CityDTO;
import com.southsmart.demo.solr.model.po.CityPO;
import com.southsmart.web.common.result.Result;
import lombok.RequiredArgsConstructor;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.awt.print.Book;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author clm
* @version 1.0
* @since 2021/9/7
*/
@RestController
@RequestMapping("citySolr")
@RequiredArgsConstructor
public class CitySolrController {
@Autowired
private SolrClient solrClient;
@Autowired
private CityMapper cityMapper;
/**
* 刪除或者修改
* @return
*/
@PostMapping("addCity")
public Result add() {
try {
List<CityPO> poList=cityMapper.selectList(new QueryWrapper<>());
List<CityDTO> dtoList=new ArrayList<>();
for (CityPO cityPO:poList){
CityDTO cityDTO= BeanUtil.copyProperties(cityPO,CityDTO.class);
dtoList.add(cityDTO);
}
solrClient.addBeans(dtoList);
solrClient.commit();
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return Result.ok();
}
/**
* 根据id查询
* @param id
* @return
* @throws IOException
* @throws SolrServerException
*/
@GetMapping("get/{id}")
public Result get(@PathVariable String id) throws IOException, SolrServerException {
SolrDocument solrDocument = solrClient.getById(id);
System.out.println(solrDocument.getFieldNames());
return Result.ok(solrDocument);
}
/**
* 根据id删除
* @return
* @throws IOException
* @throws SolrServerException
*/
@GetMapping("delete")
public Result delete() throws IOException, SolrServerException {
List<CityPO> poList=cityMapper.selectList(new QueryWrapper<>());
List<String> ids=poList.stream().map(m->m.getId()).collect(Collectors.toList());
solrClient.deleteById(ids);
solrClient.commit();
return Result.ok();
}
/**
* 查询
* @param fieldName
* @param mergerName
* @param rows
* @param startRow
* @return
* @throws IOException
* @throws SolrServerException
*/
@GetMapping("search")
public Result search(@RequestParam String fieldName ,@RequestParam String mergerName,Integer rows,Integer startRow) throws IOException, SolrServerException {
SolrQuery solrQuery = new SolrQuery();
//solrQuery.setQuery("mergerName:"+mergerName+" or name:"+mergerName);
solrQuery.setQuery(fieldName+":"+mergerName);
solrQuery.setRows(rows);
solrQuery.setStart(startRow);
// solrQuery.addHighlightField("mergerName");
// //设置高亮的样式
// solrQuery.setHighlightSimplePre("<font color='red'>");
// solrQuery.setHighlightSimplePost("</font>");
// System.out.println(solrQuery);
QueryResponse response = solrClient.query(solrQuery);
return Result.ok(response.getResults());
}
}
对比
上手难度
1、Solr和Es安装及配置基本都差不多 开箱即用
2、新增、查询等操作也类似
综上 上手难度差不多
性能
当单纯的对已有数据进行搜索时,Solr更快。
当实时建立索引时, Solr会产生io阻塞,查询性能较差, Elasticsearch具有明显的优势。
随着数据量的增加,Solr的搜索效率会变得更低,而Elasticsearch却没有明显的变化。
综上所述,Solr的架构不适合实时搜索的应用。
流行度
Es是当今的主流