• 全文检索技术ElasticSearch


    第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依赖包:

    <!-- elasticsearch  -->

    <dependency>

        <groupId>org.elasticsearch</groupId>

        <artifactId>elasticsearch</artifactId>

        <version>2.4.0</version>

    </dependency>

    <dependency>

        <groupId>org.springframework.data</groupId>

        <artifactId>spring-data-elasticsearch</artifactId>

        <version>2.0.4.RELEASE</version>

    </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">

       

        <!-- 搜索DAO 扫描 -->

        <elasticsearch:repositories base-package="cn.peihua.bos.index" />

       

        <!-- 配置Client -->

        <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中引入:

    <!-- 引入elasticSearch -->

    <import resource="applicationContext-elasticsearch.xml"/>

     

    1.5.3编写domain

    说明:本次案例数据访问技术选用的是Hibernate注解方式
     

    实体映射关系:

    @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<WayBill, Integer> {

     

    }

     

     

    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> findPageData(WayBill wayBill, Pageable pageable) {

           //判断是否是条件查询,即判断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);

              

           }

        }

     

     



  • 相关阅读:
    洛谷P2894 [USACO08FEB]酒店Hotel
    codevs 3981 动态最大子段和
    舞蹈家怀特先生(线型)
    IOS8 通知中心(Notification Center)新特性
    WWDC2014 IOS8 APP Extensions
    IOS8 TouchID使用介绍
    IOS8 UIAlertController 弹框
    Unable to run Kiwi tests on iOS8 device
    registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later
    iOS开发---- 开发错误汇总及解决方法
  • 原文地址:https://www.cnblogs.com/toby-ruan/p/8919636.html
Copyright © 2020-2023  润新知