第1章 全文检索技术
1.1概述
现在企业开发中,更常用是的 solr 搜索服务器和 ElasticSearch 搜索服务器
是通过Resyful风格API简化客户端 对lunence的使用
1.1.1和数据库进行对比分析
索引:相当于DB 存储数据的逻辑位置
类型:相当于表 ·
文档:相当于行数据,通过词条搜索出来数据
文档的属性field:相当于表中的列
服务的默认端口是: 9300
控制页面的端口号是: 9200
1.2ElasticSearch 搜索服务器安装
官网: https://www.elastic.co/products/elasticsearch
包结构:
bin 存放 elasticSearch 运行命令
config 存放配置文件
lib 存放 elasticSearch 运行依赖 jar 包
modules 存放 elasticSearch 模块
plugins 存放插件
环境配置:
运行 elasticSearch/bin/elasticsearch.bat 文件
配置 JAVA_HOME 环境变量
访问 http://127.0.0.1:9200
1.3. ElasticSearch 插件安装 es head图形化界面
1.3.1在线下载安装
1.进入到bin目录
2.执行plugin.bat install mobz/elasticsearch-head
3.将head插件安装到plugins目录下
1.3.2 如果在线安装失败
1.将head下载到本地
2.将head插件放置到plugins中即可
访问:http://localhost:9200/_plugin/head/
看到下图表示安装成功:
1.4集成IK分词器
1.4.1下载开源包
https://github.com/medcl/elasticsearch-analysis-ik/tree/2.x
1.4.2打包 ik 分词器
输入命令:mvn clean package
1.4.3进入 ik包中的target/release 目录
将下列文件,复制到EslasticSerarch文件夹的plugins/analysis-ik中
1.4.4进入 IK目录下target/release/config 目录
将所有配置文件,复制到EslasticSerarch文件夹的config 下
1.4.5在配置 ES/config/elasticsearch.yml
在其最底下加入:
index.analysis.analyzer.ik.type: "ik" |
重启ES发现 ik 分词器被加载
1.4.6访问:
http://localhost:9200/_analyze?analyzer=ik&pretty=true&text=我是中国人
集成成功
1.5Spring data ElasticSearch的使用
1.5.1导入Maven依赖包:
<dependency> <groupId>org.elasticsearchgroupId> <artifactId>elasticsearchartifactId> <version>2.4.0version> dependency> <dependency> <groupId>org.springframework.datagroupId> <artifactId>spring-data-elasticsearchartifactId> <version>2.0.4.RELEASEversion> dependency> |
1.5.2配置文件
applicationContext-elasticsearch.xml:
xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd">
<elasticsearch:repositories base-package="cn.peihua.bos.index" />
<elasticsearch:transport-client id="client" cluster-nodes="127.0.0.1:9300"/>
<bean id="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate"> <constructor-arg name="client" ref="client"/> bean> beans> |
在applicationContext.xml中引入:
|
1.5.3编写domain
实体映射关系:
@Document 文档对象 (索引名、文档类型 )
@Id 文档主键 唯一标识
注意:
实体类中不光需要导入jpa的@id还需要@org.springframework.data.annotation.Id的
id注解
@Field 每个文档的字段配置(类型、是否分词、是否存储、分词器
Field属性:说明
index = FieldIndex.not_analyzed 表示不分词
index = FieldIndex.analyzed 表示今次那个分词
store = true 表示进行ES存储
analyzer = "ik" 表示存储的分词器为ik
searchAnalyzer = "ik" 表示查询的分词器为ik
注意:
数字类型(Integer/Double)的字段不能进行分词
package cn. peihua.bos.domain.take_delivery;
import java.io.Serializable;
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldIndex; import org.springframework.data.elasticsearch.annotations.FieldType;
import cn.peihua.bos.domain.base.Area;
/** * @description:运单实体类 */ @Entity @Table(name = "T_WAY_BILL") @Document(indexName = "bos", type = "waybill") publicclass WayBillimplements Serializable {
@Id @GeneratedValue @Column(name = "C_ID") @org.springframework.data.annotation.Id @Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.Integer) private Integer id; @Column(name = "C_WAY_BILL_NUM", unique = true) @Field(index = FieldIndex.not_analyzed, store = true, type = FieldType.String) private String wayBillNum; // 运单编号 @OneToOne @JoinColumn(name = "C_ORDER_ID") private Order order; // 订单信息
@Column(name = "C_SEND_NAME") @Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String) private String sendName; // 寄件人姓名 @Column(name = "C_SEND_MOBILE") @Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String) private String sendMobile;// 寄件人电话 @Column(name = "C_SEND_COMPANY") @Field(index = FieldIndex.analyzed, analyzer = "ik", searchAnalyzer = "ik", store = true, type = FieldType.String) private String sendCompany;// 寄件人公司
……………………
|
1.5.4编写索引库dao
注意:这个索引的dao不要和原先的dao放在一个包下
package cn.peihua.bos.index;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import cn.peihua.bos.domain.take_delivery.WayBill;
publicinterface WayBillIndexRepository extends ElasticsearchRepository
}
|
1.5.5编写service
在service中注入WayBillIndexRepository
在保存进数据库的同时保存索引库
//注入索引dao @Autowired private WayBillIndexRepository wayBillIndexRepository; 在方法中直接进行调用: wayBillRepository.save(wayBill);
|
1.6进行ElasticSearch查询
1.6.1查询方式
建议:
查询可以结合分词结果查看,有助于查询结果判断
http://localhost:9200/_analyze?analyzer=ik&pretty=true&text=我是中国人
TermQuery 不能带条件的词条等值查询
WildcardQuery 模糊查询
BooleanQuery 布尔查询:可以用来组合多个查询条件
//must 条件必须成立 相当于 and
//must not 条件必须不成立 相当于 not
//should 条件可以成立 相当于or
QueryBuileders.queryStringQuery(内容) 分词查询方法 默认范围是全字段,也可以指定字段
如果是默认分词器:就按单个字查询
如果是ik分词器:就是 可以带条件 的分词等值查询
//有条件分页查询运单 public Page //判断是否是条件查询,即判断wayBill中,条件是否存在 if (StringUtils.isBlank(wayBill.getWayBillNum()) && StringUtils.isBlank(wayBill.getSendAddress()) && StringUtils.isBlank(wayBill.getRecAddress()) && StringUtils.isBlank(wayBill.getSendProNum()) && (wayBill.getSignStatus() == null || wayBill.getSignStatus() == 0)) { //无条件,直接分页查询数据库 returnwayBillRepository.findAll(pageable); }else{ //查询条件 //must 条件必须成立相当于 and //must not 条件必须不成立相当于 not //should 条件可以成立相当于or
//创建条件组合查询对象boolQuery BoolQueryBuilder query = new BoolQueryBuilder();
//构建组合条件,并将其加入到组合对象中:
//1.等值查询运单号 if(StringUtils.isNoneBlank(wayBill.getWayBillNum())){ //如果订单号不为空,就进行等值查询
//创建无条件等值查询对象 QueryBuilder termQuery = new TermQueryBuilder("wayBillNum", wayBill.getWayBillNum()); query.must(termQuery);
} //2.查询发货地 if(StringUtils.isNoneBlank(wayBill.getSendAddress())){ //如果发货地址不为空,进行查询
//情况一:用户输入的‘北’ 仅是次词条的一部分,使用模糊查询
//创建模糊查询对象 QueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder( "sendAddress", "*"+wayBill.getSendAddress()+"*");
//情况二:用户输入‘北京市海淀区’,是多个词条的组合,使用带条件的等值查询 //.feild()指定查询字段 QueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(wayBill.getSendAddress()) .field("sendAddress") .defaultOperator(Operator.AND); //对两种情况取(should)or BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolQueryBuilder.should(wildcardQueryBuilder); boolQueryBuilder.should(queryStringQueryBuilder);
//加入总条件查询对象中 query.must(boolQueryBuilder);
} //3.查询收货地 if(StringUtils.isNoneBlank(wayBill.getRecAddress())){ //如果发货地址不为空,进行查询
//情况一:用户输入的‘北’ 仅是次词条的一部分,使用模糊查询
//创建模糊查询对象 QueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder( "recAddress", "*"+wayBill.getRecAddress()+"*");
//情况二:用户输入‘北京市海淀区’,是多个词条的组合,使用带条件的等值查询 //.feild()指定查询字段 QueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(wayBill.getRecAddress()) .field("recAddress") .defaultOperator(Operator.AND); //对两种情况取(should)or BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolQueryBuilder.should(wildcardQueryBuilder); boolQueryBuilder.should(queryStringQueryBuilder);
//加入总条件查询对象中 query.must(boolQueryBuilder);
} //4.等值查询产品类型编号 if (StringUtils.isNoneBlank(wayBill.getSendProNum())) { // 速运类型等值查询 QueryBuilder termQuery = new TermQueryBuilder("sendProNum", wayBill.getSendProNum()); query.must(termQuery); } //等值查询运单签收状态 if(wayBill.getSignStatus() != null && wayBill.getSignStatus() != 0){ //如果运单签收状态不为空,进行无条件的等值查询 QueryBuilder TermQuery = new TermQueryBuilder("signStatus", wayBill.getSignStatus());
query.must(TermQuery); }
SearchQuery searchQuery = new NativeSearchQuery(query); searchQuery.setPageable(pageable); // 分页效果 // 有条件查询、查询索引库 returnwayBillIndexRepository.search(searchQuery);
} } |