全文搜索引擎技术详解Apache Solr的使用

网友投稿 671 2022-05-29

Solr

Solr是一个可扩展的,可部署,搜索,存储引擎,优化搜索大量以文本为中心的数据库

Solr是开源搜索平台,用于构建搜索应用程序

建立在Lucene(全文搜索引擎)之上

Solr是企业级的,快速的和高度可扩展的,使用Solr构建的应用程序可以提供高性能,但是非常复杂

Solr可以和Hadoop一起使用:由于Hadoop处理大量数据,Solr可以从大的数据源中找到所需信息.

Solr不仅限于搜索,也可以用于存储.和其它NoSQL数据库一样,是一种非关系数据存储和处理技术

Apache Solr特点

Solr是Lucene的Java API包装,使用Solr,就可以使用Lucene的所有功能

RESTful API: 要与Solr通信,可以使用RESTful服务与Solr通信,可以使用XML,JSON,CSV等格式的文件作为输入文档,并以相同的文件格式获取结果

全文搜索: Solr提供了全文搜索所需的所有功能:令牌,短语,拼写检查,通配符,自动完成

企业准备: 根据企业或组织的需要,Solr可以部署在任何类型的系统:独立,分布式,云

灵活可扩展: 通过扩展Java类并进行相关配置,可以定制Solr组件

NoSQL数据库: Solr可以用作大数量级的NoSQL数据库,可以沿着集群分布搜索任务

搜索引擎

搜索引擎:

搜索引擎是庞大的互联网资源数据库,如网页,新闻组,程序,图像等

有助于在网上定位信息

用户可以通过以关键字或短语的形式将查询传递到搜索引擎中来搜索信息,然后搜索引擎搜索其数据库并向用户返回相关链接

搜索引擎组件

搜索引擎有三个组件:

Web爬虫: 一个收集网络信息的软件组件

数据库: Web上的所有信息都存储在数据库中,包含大量的Web资源

搜索接口: 这个组件是用户和数据库之间的接口,帮助用户搜索数据库

搜索引擎工作流程

获取原始内容: 任何搜索应用程序的第一步是收集要进行搜索的目标内容

构建文档: 从原始内容构建文档,让搜索应用程序可以很容易的理解和解释

分析文档: 在索引开始之前,将对文档进行分析

索引文档: 当文档被构建和分析后,下一步是对文档建立索引,以便可以基于特定键而不是文档的全部内容来检索该文档.索引类似于在书开始页或末尾处的目录索引,其中常见单词以页码显示,使得这些单词可以快速追踪,而不是搜索整本书

用于搜索的用户接口: 当索引数据库就绪,应用程序就可以执行搜索操作.为了帮助用户进行搜索,应用必须提供用户接口,用户可以在用户接口中输入文本并启动搜索过程

构建查询: 当用户做出搜索文本的请求,应用程序应该使用该文本准备查询对象,然后可以使该查询对象来查询索引数据库以获得相关细节

搜索查询: 使用查询对象,检查索引数据库以获取相关详细信息和内容文档

渲染结果: 当收到所需结果,应用程序应决定如何使用用户界面向用户显示搜索结果

分词技术

分词技术: 搜索引擎针对用户提交查询的关键词串进行的查询处理后,根据用户的关键词串用各种匹配方法进行分词的一种技术

中文分词算法

基于字符串匹配:

即扫描字符串,如果发现字符串的子串和词相同,就算匹配

这类分词通常会加入一些启发式规则:正向/反向最大匹配,长词优先等

基于字符串匹配算法优点:

速度快

都是O(n)时间复杂度

实现简单

效果尚可

全文搜索引擎技术详解之Apache Solr的使用

基于字符串匹配算法缺点:

对歧义和未登录词处理不好

ikanalyzer,paoding等就是基于字符串匹配的分词

基于统计及机器学习的分词方式:

基于人工标注的词性和统计特征,对中文进行建模. 即根据观测到的数据(标注好的语料)对模型参数进行估计.即 训练

在分词阶段再通过模型计算各种分词出现的概率,将概率最大的分词结果作为最终结果

常见的序列标注模型:HMM,CRF

基于统计及机器学习的分词方式优点:

可以很好地处理歧义和未登录问题

效果比基于字符串匹配算法更好

基于统计及机器学习的分词方式缺点:

需要大量的人工标注数据

较慢的分词速度

IKAnalyzer

IKAnalyzer是一个开源的,基于Java语言开发的轻量级中文分词工具包

基于文本匹配,不需要投入大量的人力进行训练和标注

可以自定词典,方便加入特定领域的词语,能分出多粒度的结果

部署Solr并安装IKAnalyzer

创建/usr/local/docker/solr/ikanalyzer目录

/usr/local/docker/solr 用于存放docker-compose.yml配置文件 /usr/local/docker/solr/ikanalyzer 用于存放Dockerfile镜像配置文件

docker-compose.yml

version: '3.1' services: solr: build: ikanalyzer restart: always container_name: solr ports: - 8983:8983 volumes: - ./solrdata:/opt/solrdata

Dockerfile(在/usr/local/docker/solr/ikanalyzer中需要有文件:ik-analyzer-solr5-5.x.jar,solr-analyzer-ik-5.1.0.jar,ext.dic,stopword.dic,IKAnalyzer.cfg.xml,managed-schema)

FROM solr # 创建Core WORKDIR /opt/solr/server/solr RUN mkdir ik_core WORKDIR /opt/solr/server/solr/ik_core RUN echo 'name=ik_core' > core.properties RUN mkdir data RUN cp -r ../configsets/sample_techproducts_configs/conf/ . # 安装中文分词 WORKDIR /opt/solr/server/solr-webapp/webapp/WEB-INF/lib ADD ik-analyzer-solr5-5.x.jar . ADD solr-analyzer-ik-5.1.0.jar . WORKDIR /opt/solr/server/solr-webapp/webapp/WEB-INF ADD ext.dic . ADD stopword.dic . ADD IKAnalyzer.cfg.xml . # 增加分词配置 COPY managed-schema /opt/solr/server/solr/ik_core/conf WORKDIR /opt/solr

构建镜像: 在/usr/local/docker/solr中执行命令

docker-compose up -d

Solr分析功能

修改managed-schema配置业务系统字段

Solr中自带的相同字段无需再添加,其它字段需要手动添加Solr字段(通过编辑managed-schema配置文件来手动添加Solr字段)

复制配置到容器

docker cp managed-schema solr:/opt/solr/server/solr/ik_core/conf

重启容器

docker-compose restart

在Solr的Web界面可以进行CRUD操作

SpringBoot整合Solr

创建搜索服务接口

创建myshop-service-search-api项目,该项目只负责定义定义接口

pom.xml

4.0.0 com.funtl myshop-dependencies 1.0.0-SNAPSHOT ../myshop-dependencies/pom.xml myshop-service-search-api jar

在项目中创建SearchService接口

package com.oxford.myshop.service.search.api; public interface SearchService { List search(String query,int page,int rows); }

创建TbItemResult用于返回Solr结果集

package com.oxford.myshop.service.search.domain; import java.io.Serializable; public class TbItemResult implements Serializable { private long id; private long tbTtemCid; private String tbItemCname; private String tbItemTitle; private String tbItemSellPoint; private String tbItemDesc; public long getId(){ return id; } public void setId(long id){ this.id=id; } public long getTbTtemCid(){ return tbTtemCid; } public void setTbTtemCid(long tbTtemCid){ this.tbTtemCid=tbTtemCid; } public String getTbItemCname(){ return tbItemCname; } public void setTbItemCname(String tbItemCname){ this.tbItemCname=tbItemCname; } public String getTbItemTitle(){ return tbItemTitle; } public void setTbItemTitle(String tbItemTitle){ this.tbItemTitle=tbItemTitle; } public String getTbItemSellPoint(){ return tbItemSellPoint; } public void setTbItemSellPoint(String tbItemSellPoint){ this.tbItemSellPoint=tbItemSellPoint; } public String getTbItemDesc(){ return tbItemDesc; } public void setTbItemDesc(String tbItemDesc){ this.tbItemDesc=tbItemDesc; } }

创建搜索服务提供者

创建myshop-service-search-provider服务提供者项目

MyShopServiceSearchProviderApplication

package com.oxford.myshop.service.search.provider; @EnableHystrix @EnableHystrixDashboard @SpringBootApplication(scanBasePackages="com.oxfrod.myshop") @MapperScan(basePackages="com.oxford.myshop.service.search.provider.mapper") public class MyShopServiceSearchProviderApplication { public static void main(String[] args) { SpringApplication.run(MyShopServiceSearchProviderApplication.class,args); Main.main(args); } }

在项目中创建TbItemResultMapper接口用于查询MySQL中的数据,用于插入到Solr数据库中

package com.oxford.myshop.service.search.provider.mapper; @Respository public interface TbItemResultMapper { List selectAll(); }

Spring的四大注解: 1. @Controller 2. @Service 3. @Component 4. @Repository

在resource中创建mapper包用于创建TbContentCategoryMapper.xml

初始化Solr: public void initSolr() { List tbItemResult=tbItemResultMapper.selectAll(); try{ SolrInputDocument document=null; for(TbItemResult tbItemResult:tbItemResults){ document=new SolrInputDocument(); document.addFiled("id",tbItemResult.getId()); document.addFiled("tb_item_cid",tbItemResult.getTbItemCid()); document.addFiled("tb_item_cname",tbItemResult.getTbItemCname()); document.addFiled("tb_item_title",tbItemResult.getTbItemTitle()); document.addFiled("tb_item_sell_point",tbItemResult.getTbItemSellPoint()); document.addFiled("tb_item_desc",tbItemResult.getTbItemDesc()); solrClient.add(document); solrClient.commit(); } }catch(SolrServerException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 搜索Solr: public void searchSolr(){ SolrQuery query=new SolrQuery(); // 设置查询条件 query.setQuery("手机"); // 分页查询 query.setStart(0); query.setRows(10); // 设置查询的默认域 query.set("df","tb_item_keywords"); // 设置高亮显示 query.setHighlight(true); query.addHighlightField("tb_item_title"); query.setHighlightSimplePre(""); query.setHighlightSimplePost(""); // 开始查询 try{ QueryResponse queryResponse=solrClient.query(query); SolrDocumentList results=queryResponse.getResults(); // 获取高亮 Map>> highlighting=queryResponse.getHighlighting(); for(SolrDocument result:results){ List strings=highlighting.get(result.get("id")).get(result.get("tb_item_title")) if(strings!=null&&strings.size()>0){ String title=strings.get(0); System.out.println(title); } } }catch(SolrServerException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } }

创建SearchServiceImpl实现SearchService接口

package com.oxford.myshop.service.search.provider.api.impl; @Service(version="${services.versions.search.v1}") public class SearchServiceImpl implements SearchService{ @Autowired private SolrClient solrClient; @Override public List search(String query,int page,int rows){ List searchResults=Lists.newArrayList(); SolrQuery query=new SolrQuery(); // 设置查询条件 query.setQuery("手机"); // 分页查询 query.setStart((page-1)*rows); query.setRows(rows); // 设置查询的默认域 query.set("df","tb_item_keywords"); // 设置高亮显示 query.setHighlight(true); query.addHighlightField("tb_item_title"); query.setHighlightSimplePre(""); query.setHighlightSimplePost(""); // 开始查询 try{ QueryResponse queryResponse=solrClient.query(query); SolrDocumentList results=queryResponse.getResults(); // 获取高亮 Map>> highlighting=queryResponse.getHighlighting(); for(SolrDocument solrDocument:solrDocuments){ TbItemResult result=new TbResult(); result.setId(Long.parseLong(String.valueOf(solrDocument.get("id")))); result.setTbItemCid(Long.parseLong(String.valueOf(solrDocument.get("tb_item_cid")))); result.setTbItemCname((String)solrDocument.get("tb_item_cname")); result.setTbItemTitle((String)solrDocument.get("tb_item_title")); result.setTbItemSellPoint((String)solrDocument.get("tb_item_sell_point")); result.setTbItemDesc((String)solrDocument.get("tb_item_desc")); String tbItemTitle=""; List list=highlighting.get(result.get("id")).get(result.get("tb_item_title")) if(list!=null&&lsit.size()>0){ String title=list.get(0); }else{ tbItemTitle=(String)solrDocument.get("tb_item_title"); } result.setTbItemTitle(tbItemTitle); searchResults.add(result); } }catch(SolrServerException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } return searchResults; } }

创建搜索服务消费者

创建搜索服务消费者myshop-service-search-consumer对Solr数据库中的数据进行检索

MyShopServiceSearchConsumerApplication

package com.oxford.myshop.service.search.consumer; @EnableHystrix @EnableHystrixDashboard @SpringBootApplication(scanBasePackages="com.oxford.myshop",exclude=DataSourceAutoConfiguration.class) public class MyShopServiceSearchConsumerApplication{ public static void main(String[] args){ SpringApplication.run(MyShopServiceSearchConsumerApplication.class,args); Main.main(args); } }

SearchController

package com.oxford.myshop.service.search.consumer.controller; @RestController public class SearchController{ @Reference(version="${services.versions.search.v1}") private SearchService searchService; @RequestMapping(value="search/{query}/{page}/{rows}",method=RequestMethod.GET) public List search( @PathVariable(required=true) String query, @PathVariable(required=true) int page, @PathVariable(required=true) int rows ){ return searchService.search(query,page,rows) } }

Apache Lucene/Solr 搜索引擎 数据库

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Android 程序崩溃之快速锁定!
下一篇:《TCP/IP详解 卷2:实现》 —2.11 小结
相关文章