elasticsearch 实现联想输入搜索

您所在的位置:网站首页 java实现关键词搜索 elasticsearch 实现联想输入搜索

elasticsearch 实现联想输入搜索

2024-06-04 12:54| 来源: 网络整理| 查看: 265

通常,在项目中需要联想输入(即输入关键字,提示相关词条,类似百度google的搜索)的需求,可能大家都是用的数据库的like '%关键字%‘来实现。但是这样实现有几个问题。

第一、这样的搜索无论是oracle还是mysql,都是无法使用索引的。在oracle中可能有全文检索可以使用,但是个人感觉效果不是很好。

第二、输入的关键字有like的通病,就是只有保含关键字的词条才会被命中。如果中间加个空格之类的,db就无能为力了。

第三、如果要想对命中结果进行相关度排序,这个在常规数据库是无法做到的。虽然,可以按照命中词条的长度进行升序排序,但是加上排序,性能不是很好。

下面介绍一下使用elasticsearch实现联想输入的搜索,因为是搜索引擎,天生就不具备上面的3个问题。

在具体介绍使用方法之前,我们先找个搜索数据。我找的是ICD(就是疾病名称的国标),谁让咱一生都在跟他做斗争。这个在网上一搜一堆。

有了数据,我们先要简单描述一下我们要达到的一个目的。一般的搜索都支持汉字 和拼音两种检索方法。我们的这个检索也满足这个需求。

搜索需求描述:

1、支持汉字和简拼两种搜索方法。

2、输入“高血压”时,按照相关度,将带“高血压”名称的疾病名称按照相关度降序排序。

3、输入“老年 高血压”,时,将带“老年”和“高血压”名称的疾病名称按照相关度降序排序。

4、输入拼音'gxy‘时,将拼音中带有gxy相关的疾病按照相关度降序排序。

....

类似测试用例的需求,到此打住。

那么,我们一步一步实现这种需求。

首先,我们定义了一个ICD的类,算作我们的模型,其实没有模型也可以,只要存入到es且知道各个field的名称就行。这个里面我们只需要关注疾病名称diseaseName及简拼pinyin字段即可,这个字段默认是字符串,ES默认会帮我们分词。

Java代码

import java.io.Serializable;  

import java.math.BigDecimal;  

/**

* ICD抽象对象

* @author [email protected]

*/  

public class ICD implements Serializable{  

   private static final long serialVersionUID = 6934803011248581109L;  

   //疾病ID  

   private int id;  

   //疾病编码  

   private String code;  

   //疾病名称  

   private String diseaseName;  

   //疾病加拼音  

   private String mergeName;  

   //汉语拼音简拼  

   private String pinyin;  

   //是否恶心肿瘤  

   private boolean isTherioma;  

   //是否住院特殊病种  

   private boolean isSpecialDisease;  

     

   public ICD(BigDecimal id, String diseaseName, String code,  

           String pinyin, String isTherioma, String isSpecialDisease) {  

       this.id = id.intValue();  

       this.diseaseName = diseaseName;  

       this.code = code;  

       this.pinyin = pinyin;  

       if("是".equals(isTherioma)){  

           this.isTherioma = true;  

       }  

       else {  

           this.isTherioma = false;  

       }  

         

       if("是".equals(isSpecialDisease)){  

           this.isSpecialDisease = true;  

       }  

       else {  

           this.isSpecialDisease = false;  

       }  

       this.mergeName = diseaseName + "," + pinyin;  

   }  

   //set,get ......  

     

}  

第二步,将数据存储到elasticsearch里面,我们取个名称叫code,起个type名称叫icd。ICD大概2w条数据,我使用默认的bulkIndex,存到es大概用了3秒。

我这里是把数据从oracle导入到elasticsearch。

Java代码

import java.math.BigDecimal;  

import java.sql.Connection;  

import java.sql.PreparedStatement;  

import java.sql.ResultSet;  

import java.util.ArrayList;  

import java.util.List;  

 

import org.elasticsearch.action.bulk.BulkRequestBuilder;  

import org.elasticsearch.action.bulk.BulkResponse;  

import org.elasticsearch.action.index.IndexRequestBuilder;  

import org.elasticsearch.client.Client;  

 

import com.donlianli.es.ESUtils;  

import com.donlianli.es.db.DatabaseUtils;  

 

public class ICDManager {  

     

   public static void main(String[] argvs){  

       ICDManager manager = new ICDManager();  

       manager.indexDataDirect();  

   }  

   /**

    * 直接将数据初始化到ES中

    * 不创建mapping

    */  

   private void indexDataDirect() {  

       List icdList = getIcdListFromDB();    

       System.out.println(" get icd from db finish,size:" + icdList.size());  

       bulkIndex(icdList);  

   }  

     

   private void bulkIndex(List icdList) {  

       Client client = ESUtils.getCodeClient();  

       BulkRequestBuilder bulkRequest = client.prepareBulk();  

       long b = System.currentTimeMillis();  

       for(int i=0,l=icdList.size();i



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3