欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

什么是Solr

程序员文章站 2022-06-30 13:52:02
什么是Solr Lucene复习: 1、什么是lucene:全文检索工具包 2、Lucene的工作原理: 索引数据的创建 从原始文件中提取一些可以用来搜索的数据(封装成各种Field),把各field再封装成document,然后对document进行分析(对各字段分词),得到一些索引目录写入索引库 ......

lucene复习:

1、什么是lucene:全文检索工具包

2、lucene的工作原理:

索引数据的创建

从原始文件中提取一些可以用来搜索的数据(封装成各种field),把各field再封装成document,然后对document进行分析(对各字段分词),得到一些索引目录写入索引库,document本身也会被写入一个文档信息库;

索引数据的查询

根据关键词解析(queryparser)出查询条件query(termquery),利用搜索工具(indexsearcher)去索引库获取文档id,然后再根据文档id去文档信息库获取文档信息

分词器不同,建立的索引数据就不同;比较通用的一个中文分词器ikanalyzer的用法

3、相关度得分

a) 在建立索引的时候,给指定文档的指定域设置一个权重

field.setboosts()

b) 在搜索的时候,可以给不同的搜索域设置不同的权重

boosts = new hashmap<string,float>

multifieldsqueryparser(fields,analyzer,boosts)

solr笔记

课程计划

1、站内搜索技术选型。

2、solr相关概念

3、solr的安装及配置

solr整合tomcat

4、solr后台管理界面的功能介绍

a) 维护索引

b) 查询索引

5、solr实现索引库的维护

a) 增删改操作

b) 批量添加数据,从数据库中把数据导入到索引库。dataimport插件。

6、索引库的查询

7、solrj客户端,

a) 索引库的维护

b) 索引库的查询

8、综合案例,电商网站的搜索。

站内搜索技术选型

1、lucene:可以实现站内搜索。需要大量的开发工作。索引库的维护及优化。查询的优化等问题都需要我们自己来解决。不推荐使用。

2、使用第三方搜素引擎实现。使用百度实现站内搜索。免费的。索引库无法维护。适合一些小的网站。不推荐使用。

3、solr:基于solr实现站内搜索扩展性较好并且可以减少程序员的工作量,因为solr提供了较为完备的搜索引擎解决方案,因此在门户、论坛等系统中常用此方案。提供了完整的集群方案,和索引库优化方案。

什么是solr

为什么要solr:

1、solr是将整个索引操作功能封装好了的搜索引擎系统(企业级搜索引擎产品)

2、solr可以部署到单独的服务器上(web服务),它可以提供服务,我们的业务系统就只要发送请求,接收响应即可,降低了业务系统的负载

3、solr部署在专门的服务器上,它的索引库就不会受业务系统服务器存储空间的限制

4、solr支持分布式集群,索引服务的容量和能力可以线性扩展

solr的工作机制:

1、solr就是在lucene工具包的基础之上进行了封装,而且是以web服务的形式对外提供索引功能

2、业务系统需要使用到索引的功能(建索引,查索引)时,只要发出http请求,并将返回数据进行解析即可

solr 是apache下的一个*开源项目,采用java开发,它是基于lucene的全文搜索服务器。solr提供了比lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化。

solr可以独立运行,运行在jetty、tomcat等这些servlet容器中,solr 索引的实现方法很简单,用 post 方法向 solr 服务器发送一个描述 field 及其内容的 xml 文档,solr根据xml文档添加、删除、更新索引 。solr 搜索只需要发送 http get 请求,然后对 solr 返回xml、json等格式的查询结果进行解析,组织页面布局。solr不提供构建ui的功能,solr提供了一个管理界面,通过管理界面可以查询solr的配置和运行情况。

就是一个web工程

solr和lucene区别

lucene是一个开放源代码的全文检索引擎工具包,它不是一个完整的全文检索引擎,lucene提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以lucene为基础构建全文检索引擎。

solr的目标是打造一款企业级的搜索引擎系统,它是一个搜索引擎服务,可以独立运行,通过solr可以非常快速的构建企业的搜索引擎,通过solr也可以高效的完成站内搜索功能。

solr的下载

最新版:5.3.1

本课程的版本:4.10.3

solr的安装及配置

安装solr,就是去部署它的war包,war包所在的位置如图:

开发环境

jdk:1.7以上。1.7.0_72

tomcat:7以上。apache-tomcat-7.0.53

solr:4.10.3

solr集成tomcat

第一步:安装tomcat,建议安装一个全新的tomcat。

第二步:上传solr安装压缩包到服务器上,然后解压

unzip -q /root/solr-4.10.3.zip

第三步:在tomcat的webapps中事先建立一个solr工程文件夹

mkdir /usr/local/apache-tomcat-7.0.63/webapps/solr

然后将solr的war包解压到solr工程文件夹里面去

unzip /root/solr-4.10.3/dist/solr-4.10.3.war -d /usr/local/apache-tomcat-7.0.63/webapps/solr

然后,将日志工具jar包添加到solr的war工程的webinf的lib中

cp /root/solr-4.10.3/example/lib/ext/*.jar /usr/local/apache-tomcat-7.0.63/webapps/solr/web-inf/lib/

第四步:从solr的安装目录中拷贝一个示例solrhome到我们的服务器真实部署目录中

拷贝: cp -r /root/solr-4.10.3/example/solr /usr/local/

改名: mv /usr/local/solr/ /usr/local/solrhome

第五步:告诉solr的war工程,我们准备的solrhome目录所在的路径

vi /usr/local/apache-tomcat-7.0.63/webapps/solr/web-inf/web.xml

至此,可以启动tomcat,进行测试

了解solrhome

1、collection1:是一个solrcore,一个solrcore就是一个索引库。一个solr服务器上可以有多solrcore。每个索引库之间是相互独立的。

2、\solrhome\collection1\conf:是存放每个solrcore的个性配置。

3、solrconfig.xml

a) lucenematchversion:匹配lucene的版本信息

b) lib:solrcore扩展使用的jar包。默认值是collection1\lib,如果没有此文件夹就创建一个。

c) datadir:索引库存放的目录。默认是collection1\data文件夹。如果没有solr会自动创建。如果想修改为其他位置,需要配置此节点。

d) requesthandler:配置solr对外提供服务的url

i. <requesthandler name="/select" class="solr.searchhandler">:查询索引库使用的url

ii. <requesthandler name="/update" class="solr.updaterequesthandler">

维护索引库使用的url

e) defaultquery:管理页面默认的查询条件 *:*

4、core.properties:配置了solrcore的名字。

第六步:告诉solr工程solrhome的位置。修改solr/web-inf/web.xml文件。

第七步:启动tomcat

访问http://localhost:8080/solr

管理界面功能介绍

core admin

solrcore的管理 功能。

添加一个solrcore

添加步骤:

第一步:把collection1复制一份改名为collection2

第二步:修改core.properties。name=collection2

第三步:重启tomcat

core selecter

选择要管理哪个solrcore。

analysis

查看域的分词效果。

dataimport

可以实现把数据库中的数据导入到索引库中。

documents

索引库维护功能。

增删改查

query

索引查询功能。

索引的维护

在solr中域必须先定义后使用。而且每个document中必须有一个id域。

schema.xml

field:域的定义。

name:域的名称

type:域的类型

indexed:是否索引

stored:是否存储

multivalued:是否多值,如果是多值在一个域中可以保持多个值。

dynamicfield动态域

name:域的名称,是一个表达式。如果域的名称和表达式相匹配,此域名就可以使用。

type:域的类型

indexed:是否索引

stored:是否存储

multivalued:是否多值,如果是多值在一个域中可以保持多个值。

uniquekey

每个文档必须有一个uniquekey,而且不能重复。相当于表中的主键。

copyfield

复制域。

source:源域

dest:目标域。

创建文档时,solr会自动把源域的内容复制到目标域。使用复制域可以提供查询的性能。

fieldtype

域的类型。

name:域类型名。

class:对应的实现类。solr.textfield类似于lucene中的textfield。可以配置用户自定义的分析器。

自定义fieldtype使用中文分析器
配置中文分析器

配置步骤:

第一步:把ikanalyzer2012ff_u1.jar添加到solr工程的lib库中。

第二步:把配置文件和扩展词典、停用词词典添加到solr工程classpath下。solr/web-inf/classes。保证字典的字符集是utf-8.

配置自定义fieldtype

在schema.xml中添加如下内容:

<!-- ikanalyzer-->

<fieldtype name="text_ik" class="solr.textfield">

<analyzer class="org.wltea.analyzer.lucene.ikanalyzer"/>

</fieldtype>

<!--ikanalyzer field-->

配置自定义的域

<field name="title_ik" type="text_ik" indexed="true" stored="true" />

<field name="content_ik" type="text_ik" indexed="true" stored="false" multivalued="true"/>

重启tomcat,查看效果

淘淘商城商品信息搜索域定义

<!--product-->

<field name="product_name" type="text_ik" indexed="true" stored="true"/>

<field name="product_price" type="float" indexed="true" stored="true"/>

<field name="product_description" type="text_ik" indexed="true" stored="false" />

<field name="product_picture" type="string" indexed="false" stored="true" />

<field name="product_catalog_name" type="string" indexed="true" stored="true" />

<field name="product_keywords" type="text_ik" indexed="true" stored="false" multivalued="true"/>

<copyfield source="product_name" dest="product_keywords"/>

<copyfield source="product_description" dest="product_keywords"/>

添加文档

注意:每个文档必须有一个id域。而且域名必须在schema.xml中定义。

dataimport插件

可以批量把数据库中的数据导入到索引库中。

需要的jar包

安装步骤:

第一步:把dataimport插件依赖的jar包添加到collection1\lib文件夹下。

第二步:把mysql的数据库驱动也放到collection1\lib文件夹下

第三步:修改solrhome/collection1/conf/solrconfig.xml,添加一个requesthandler。

<requesthandler name="/dataimport"

class="org.apache.solr.handler.dataimport.dataimporthandler">

<lst name="defaults">

<str name="config">data-config.xml</str>

</lst>

</requesthandler>

第四步:创建一个data-config.xml。目录和solrconfig.xml在同一个目录下collection1\conf。

<?xml version="1.0" encoding="utf-8" ?>

<dataconfig>

<datasource type="jdbcdatasource"

driver="com.mysql.jdbc.driver"

url="jdbc:mysql://192.168.33.10:3306/taotao"

user="root"

password="root"/>

<document>

<entity name="product" query="select pid,name,catalog_name,price,description,picture from products ">

<field column="pid" name="id"/>

<field column="name" name="product_name"/>

<field column="catalog_name" name="product_catalog_name"/>

<field column="price" name="product_price"/>

<field column="description" name="product_description"/>

<field column="picture" name="product_picture"/>

</entity>

</document>

</dataconfig>

第五步:重启tomcat后,进入solr管理页面,执行数据导入

索引库的查询

查询语法支持的参数

q:主查询条件。完全支持lucene语法。还进行了扩展。

fq:过滤查询。是在主查询条件查询结果的基础上进行过滤。

sort:排序条件。排序的域asc。如果有多个排序条件使用半角逗号分隔。

start, rows:分页处理。start起始记录rows每页显示的记录条数。

fl:返回结果中域的列表。使用半角逗号分隔。

df:默认搜索域

wt:响应结果的数据格式,可以是json、xml等。

hl:开启高亮显示。

hl.fl:要高亮显示的域。

hl.simple.pre:高亮显示的前缀

hl.simple.post:高亮显示的后缀

solrj客户端

可以实现对索引库的增删改查操作。

使用步骤:

第一步:创建一java工程。

第二步:导入jar包。导入solrj的jar 包。

索引库的维护

添加文档

第1步:创建solrserver对象和服务端建立连接。httpsolrserver子类来完成。集群环境使用cloudsolrserver。

第2步:创建一文档对象。solrinputdocument。

第3步:向文档对象中添加域。使用addfield添加域。要求必须有id域,而且每个域必须在schema.xml中定义。

第4步:使用solrserver对象把文档提交到服务器。

代码实现

//添加文档对象

@test

public void adddocument() throws exception {

//创建一个solrserver对象

//参数:solr服务器的url

solrserver server = new httpsolrserver("http://localhost:8080/solr");

//创建文档对象

solrinputdocument document = new solrinputdocument();

//添加域

document.addfield("id", "num001");

document.addfield("title_ik", "巧手diy彩帘");

//把document对象写入索引库

server.add(document);

//提交修改

server.commit();

}

删除文档
根据id删除文档

//根据id删除文档

@test

public void deletedocumentbyid() throws exception {

solrserver server = new httpsolrserver("http://localhost:8080/solr");

//删除文档

server.deletebyid("num001");

//提交修改

server.commit();

}

根据查询删除文档

//根据查询删除文档

@test

public void deletedocumentbyquery() throws exception {

solrserver server = new httpsolrserver("http://localhost:8080/solr");

//根据查询条件删除

server.deletebyquery("*:*");

//提交修改

server.commit();

}

修改文档

solrj并没有一个方法可以修改文档。还是使用add方法。只需要添加一个新的文档,保证新文档的id和被修改文档的id一致即可。

本质先删除后添加。

查询索引库

实现步骤

第一步:创建一个solrserver对象。

第二步:创建一个solrquery对象。

第三步:向solrquery对象中添加查询条件。

第四步:执行查询。返回文档列表。

第五步:遍历列表。

代码实现

//简单查询

@test

public void queryindex() throws exception {

solrserver server = new httpsolrserver("http://localhost:8080/solr");

//创建一个查询对象

solrquery query = new solrquery();

//添加查询条件

//query.setquery("*:*");

query.set("q", "*:*");

//执行查询

queryresponse response = server.query(query);

//取文档列表

solrdocumentlist solrdocumentlist = response.getresults();

system.out.println("查询结果的总数量:" + solrdocumentlist.getnumfound());

//遍历列表

for (solrdocument solrdocument : solrdocumentlist) {

system.out.println(solrdocument.get("id"));

system.out.println(solrdocument.get("product_name"));

system.out.println(solrdocument.get("product_price"));

system.out.println(solrdocument.get("product_catalog_name"));

system.out.println(solrdocument.get("product_picture"));

}

}

综合案例

需求

使用solr实现电商网站中商品信息搜索功能,可以根据关键字、分类、价格范围搜索商品信息,也可以根据价格进行排序。

需求分析

开发需要的文档

1、数据库的表结构。

2、页面原型图。

3、业务流程图

页面原型分析

流程图

dao层

功能:查询solr服务返回一个商品列表。需要一个query对象,执行query对象进行查询,返回商品列表。

参数:solrquery query

返回值:resultmodel 包含商品列表

商品的pojo:

public class productmodel {

// 商品编号

private string pid;

// 商品名称

private string name;

// 商品分类名称

private string catalog_name;

// 价格

private float price;

// 商品描述

private string description;

// 图片名称

private string picture;

}

返回值pojo:

public class resultmodel {

// 商品列表

private list<productmodel> productlist;

// 商品总数

private long recordcount;

// 总页数

private int pagecount;

// 当前页

private int curpage;

}

方法定义:

resultmodel queryproduct(solrquery query) throws exception;

service

功能:接收controller传递过来的参数。创建一solrquery对象,拼装查询条件调用dao层执行查询返回一个resultmodel对象。还需要计算商品列表的总页数。

参数:

1、查询条件:string querystring

2、商品分类名称:string catalog_name

3、价格区间过滤条件:使用一个字符串来描述一个区间例如:

*-10,10-20,20-30,30-*。

string price

4、排序条件:只需要接收一个排序的方式就可以了。0:升序1:降序。 string sort

5、分页条件:接收一个页码是一个integer数据。需要我们确定每页显示商品的数量。可以定义在常量或者配置文件。每页显示60商品。integer page

返回值:resultmodel

方法定义:

resultmodel queryproduct(string querystring, string catalog_name, string price,string sort, integer page);

controller

功能:接收页面传递过来的参数,调用service查询商品列表。把查询结果传递给页面。还需要参数回显。

参数:

1. 查询条件:string querystring

2. 商品分类名称:string catalog_name

3. 价格区间过滤条件:使用一个字符串来描述一个区间例如:

*-10,10-20,20-30,30-*。

string price

4. 排序条件:只需要接收一个排序的方式就可以了。0:升序1:降序。 string sort

5. 分页条件:接收一个页码是一个integer数据。需要我们确定每页显示商品的数量。可以定义在常量或者配置文件。每页显示60商品。integer page

6、model,传递参数使用。

返回值:string(逻辑视图名)

方法定义:

public string queryproduct(string querystring, string catalog_name, string price,string sort, integer page, model model)

jsp

代码实现

实现步骤

第一步:创建一web工程

第二步:导入jar包。需要springmvc、spring、solrj、solrj依赖的jar、日志相关的jar包。

第三步:编写dao

第四步:编写service

第五步:编写controller

第六步:配置前端控制器,创建springmvc.xml配置三大件。

代码实现
dao

@repository

public class productdaoimpl implements productdao {

@autowired

private solrserver solrserver;

@override

public resultmodel queryproduct(solrquery query) throws exception {

//根据query对象查询索引库

queryresponse response = solrserver.query(query);

//取商品列表

solrdocumentlist documentlist = response.getresults();

list<productmodel> productlist = new arraylist<>();

for (solrdocument solrdocument : documentlist) {

//取商品信息

productmodel productmodel = new productmodel();

productmodel.setpid((string) solrdocument.get("id"));

//取高亮显示

string productname = "";

map<string, map<string, list<string>>> highlighting = response.gethighlighting();

list<string> list = highlighting.get(solrdocument.get("id")).get("product_name");

if (list != null && list.size() > 0) {

productname = list.get(0);

else {

productname = (string) solrdocument.get("product_name");

}

productmodel.setname(productname);

productmodel.setcatalog_name((string) solrdocument.get("product_catalog_name"));

productmodel.setprice((float) solrdocument.get("product_price"));

productmodel.setpicture((string) solrdocument.get("product_picture"));

//添加到商品列表

productlist.add(productmodel);

}

//返回值对象

resultmodel resultmodel = new resultmodel();

resultmodel.setproductlist(productlist);

//查询结果总数量

resultmodel.setrecordcount(documentlist.getnumfound());

return resultmodel;

}

}

service

@service

public class productserviceimpl implements productservice {

@autowired

private productdao productdao;

@override

public resultmodel queryproduct(string querystring, string catalog_name,

string price, string sort, integer page) throws exception {

//拼装查询条件

solrquery solrquery = new solrquery();

//查询条件

if (null != querystring && !"".equals(querystring)) {

solrquery.setquery(querystring);

else {

solrquery.setquery("*:*");

}

//分类名称过滤条件

if (null != catalog_name && !"".equals(catalog_name)) {

solrquery.addfilterquery("product_catalog_name:" + catalog_name);

}

//价格区间过滤条件

if (null != price && !"".equals(price)) {

string[] strings = price.split("-");

solrquery.addfilterquery("product_price:["+strings[0]+" to "+strings[1]+"]");

}

//排序条件

if ("1".equals(sort)) {

solrquery.setsort("product_price", order.desc);

else {

solrquery.setsort("product_price", order.asc);

}

//分页条件

if (page == null) page = 1;

int start = (page - 1) * global.page_size;

solrquery.setstart(start);

solrquery.setrows(global.page_size);

//设置默认搜索域

solrquery.set("df", "product_keywords");

//高亮显示

solrquery.sethighlight(true);

//高亮显示的域

solrquery.addhighlightfield("product_name");

//前缀

solrquery.sethighlightsimplepre("<span style=\"color:red\">");

//后缀

solrquery.sethighlightsimplepost("</span>");

//执行查询

resultmodel resultmodel = productdao.queryproduct(solrquery);

//计算总页数

long recordcount = resultmodel.getrecordcount();

int pagecount = (int) (recordcount / global.page_size);

if (recordcount % global.page_size > 0) {

pagecount ++;

}

resultmodel.setpagecount(pagecount);

resultmodel.setcurpage(page);

return resultmodel;

}

}

controller

@controller

public class productcontroller {

@autowired

private productservice productservice;

@requestmapping("/list")

public string queryproduct(string querystring, string catalog_name,

string price, string sort, integer page, model model) {

// 查询商品列表

resultmodel resultmodel = null;

try {

resultmodel = productservice.queryproduct(querystring,

catalog_name, price, sort, page);

catch (exception e) {

// todo auto-generated catch block

e.printstacktrace();

}

// 传递给页面

model.addattribute("result", resultmodel);

// 参数回显

model.addattribute("querystring", querystring);

model.addattribute("catalog_name", catalog_name);

model.addattribute("price", price);

model.addattribute("sort", sort);

model.addattribute("page", page);

// 返回jsp

return "product_list";

}

}

springmvc

<?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:mvc="http://www.springframework.org/schema/mvc"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemalocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.1.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">

<!-- 配置扫描包 -->

<context:component-scan base-package="cn..jd" />

<!-- 配置注解驱动 -->

<mvc:annotation-driven />

<!-- jsp视图解析器 -->

<bean

class="org.springframework.web.servlet.view.internalresourceviewresolver">

<!-- 前缀 -->

<property name="prefix" value="/web-inf/jsp/"></property>

<!-- 后缀 -->

<property name="suffix" value=".jsp"></property>

</bean>

<bean class="org.apache.solr.client.solrj.impl.httpsolrserver">

<constructor-arg value="http://localhost:8080/solr/"></constructor-arg>

</bean>

</beans>

web.xml

<?xml version="1.0" encoding="utf-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"

xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

id="webapp_id" version="2.5">

<display-name>solrjd0508</display-name>

<welcome-file-list>

<welcome-file>index.html</welcome-file>

<welcome-file>index.htm</welcome-file>

<welcome-file>index.jsp</welcome-file>

<welcome-file>default.html</welcome-file>

<welcome-file>default.htm</welcome-file>

<welcome-file>default.jsp</welcome-file>

</welcome-file-list>

<!-- 配置前端控制器 -->

<!-- springmvc配置 -->

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class>

<init-param>

<param-name>contextconfiglocation</param-name>

<param-value>classpath:springmvc.xml</param-value>

</init-param>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>*.action</url-pattern>

</servlet-mapping>

<filter>

<filter-name>character encoding</filter-name>

<filter-class>org.springframework.web.filter.characterencodingfilter</filter-class>

<init-param>

<param-name>encoding</param-name>

<param-value>utf-8</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>character encoding</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

</web-app>