在web开发的时候, 通常, 我们在从数据库中取出数据然后展示在页面上, 但是, 查询数据库属于耗时操作, 这种方式的效率极低, 只适用于用户访问量比较小的情况. 如果出现像淘宝,天猫618节那样用户并发访问量急剧增长的情况. 仅仅只是通过从数据库中查出数据, 已经远远满足不了用户的需求了. 所以, 我们需要建立索引来提高用户的访问速度, 而不是每个操作都需要操作数据库, 这就需要用到我接下来要讲到的全文检索技术 solr.
第一步, 先确定是否配置好java环境, 如果没有, 请先配置好
第二步, 下载tomcat, 并安装
第三步, 下载solr:
解压到当前目录, 目录结构如下:
进入dist目录,将solr-4.10.3.war
复制到tomcat的webapps目录下, 并重命名为solr.war
cp solr-4.10.3.war /usr/local/tomcat/webapps/solr.war
启动tomcat后, 该目录下会自动将solr.war解压, 生成solr文件夹, 进入到该文件夹,cd solr/WEB-INF/
, 我们将下载的solr-4.10.3该目录下solr-4.10.3/example/lib/ext
下所有的jar包复制到WEB-INF/lib
目录下,
并在WEB-INF
的目录下创建classes
文件夹,
下载solr中文分词器 IK Analyzer 2012FF_hf1.
解压后, 将IK Analyzer 2012FF_hf1
目录下的IKAnalyzer2012FF_u1.jar
复制到WEB-INF/lib
目录下, 将ext.dic, IKAnalyzer.cfg.xml, stopword.dic
复制到刚创建的WEB-INF/classes
目录下.
- 进入到solr目录下的example目录, 复制solr目录到
~/
下, 并重命名为solrhome
cp -r solr ~/solrhome
solrhome目录下有个collection1目录, 这就是我们项目所需要配置的目录.
之后我们来修改solr/WEB-INF/web.xml, 修改如下
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/home/dagger/solrhome</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
~/solrhome
就是/home/dagger/solrhome
目录这时候, 我们的solrhome目录就已经指定好了, solrhome目录.
就是我们solr的家目录,
其中的collection1就相当与一个项目工程, 如果想要新加一个collection, 我们只需将collection1复制一份到当前目录并重命名为collection2.
修改collection1/conf/schema.xml
, 如果我们要用刚刚配置的中文分词器的话, 我们需要在该配置文件做下配置,
在根节点下配置如下
<!-- 中文分词器 -->
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
重启tomcat后配置生效
访问solr项目: localhost:8080/solr
访问页面如图:
我们在左侧边栏的下拉列表core selector选中collection1, 这就是~/solrhome/collection1, 随后再选中Analysis, 我们从网上随便找一段话, 来试试中文分词的效果:
我们将语句放入Field Value (Index)文本框中, 在Analyse Fieldname / FieldType上选中 text_ik (这是我们在~/solrhome/collection/conf/schema.xml)
中配置中文分词器fieldType标签上的name属性值,
随后, 我们点击Analyse Values蓝色按钮, 进行分词. 效果如下, 感觉还不错.
接下来, 我们需要将数据库中的数据导入到solr中的collection1中
请先准备3个jar包
将这3个jar包放到solr/WEB-INF/lib
目录下, 进入到~/solrhome/collection1
, 修改solrconfig.xml
, 添加以下配置
<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
, 配置如下:
user和password根据自己的mysql用户名和密码做配置
url后写上自己的数据库名称
entity的name属性写上自己的表名称, query为sql查询语句, 查询出来的字段要对应 schema.xml
中配置的field标签中的name, 你也可以在schema.xml
中自定义field.
field 的column属性为表中的字段民, name属性对应schema.xml
中的field标签的配置
<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/boot_crm"
user=""
password=""/>
<document>
<entity name="customer" query="SELECT cust_id, cust_name, cust_source, cust_industry FROM customer">
<field column="cust_id" name="cust_id"/>
<field column="cust_name" name="cust_name"/>
<field column="cust_source" name="cust_source"/>
<field column="cust_industry" name="cust_industry"/>
</entity>
</document>
</dataConfig>
schema.xml
中对应customer表字段的配置
- type代表字段的类型, 如果type指定为text_ik, 那么表示solr按照这个字段进行分词,indexed表示是否为这个字段创建索引, sotred表示是否在solr查询的结果中显示这个字段
<!-- 中文分词器 -->
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
<!-- customer表中对应的字段 -->
<field name="cust_name" type="text_ik" indexed="true" stored="true"/>
<field name="cust_source" type="string" indexed="true" stored="true"/>
<field name="cust_industry" type="string" indexed="true" stored="true"/>
修改uniqueKey标签, 找到原来name为id的field标签, 修改如下
<!-- <uniqueKey>id</uniqueKey> -->
<uniqueKey>cust_id</uniqueKey>
...
<!-- <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> -->
<field name="cust_id" type="int" indexed="true" stored="true" required="true" multiValued="false" />
solr默认主键类型为string类型, 如果你的主键的类型为int或其它类型, 那么你需要修改solrconfig.xml配置文件, 将以下代码注释掉
<!-- 解决id非string类型报错的问题 -->
<!--
<searchComponent name="elevator" class="solr.QueryElevationComponent" >
<str name="queryFieldType">string</str>
<str name="config-file">elevate.xml</str>
</searchComponent>
-->
重起tomcat使配置生效
在Dataimport选项卡中, 确认Command为full-import, 点击Execute, 开始导入数据, 我们需要一直点击Refresh Status, 确认有成功信息为止, 表示customer表中的数据导入成功. 在Query选项卡中, 点击Execute Query, 右边就会有数据产生.
这时候, 我们就可以通过访问http://localhost:8080/solr/这个接口, 来获取数据库中的数据了, 而不需要再次从数据库中查找
我先来介绍, 如何在这个图形界面操作数据:
在Documents选项卡, 将Document Type选为xml格式,
- 根据cust_id删除索引
这时候, cust_id为17的数据就被删掉了, 这里的id指的就是cust_id, 不管你主键叫什么名字, 等价于id - 添加新索引, 将Document Type选为JSON格式,在添加的时候我们就不能使用id了, 必须指定cust_id
对于索引的操作, 我们经常用的最多的是查询操作, 所以接下来, 我将会话很多的时间讲一下, solr查询的操作
进入Query选项卡
q: 查询字符串, 必须有, 如果查询所有时使用:, 例如, cust_name为张三的数据:
cust_name:张三
fq: 过滤查询, 在q的查询结果中使用fq过滤符合条件的数据, 例如, 筛选cust_id 从1~10所有数据:
cust_id:[1 TO 10]
sort: 排序, 例如, 根据cust_id倒序排序:
cust_id desc
- start, rows: 分页展示, start:从第几条数据开始, rows:几条数据, 例如
fl: 要展示哪些字段, 字段间用逗号分隔, 例如:
cust_id, cust_name
df: 默认搜索域, 根据这个field进行搜索匹配, 指定一个schema.xml中的field的name值: 如:
cust_name
- wt: 指定输出格式,可以有 xml, json, php, phps
hl: 是否高亮 ,设置高亮Field,设置格式前缀和后缀。
当然, 我们在项目开发的过程中, 不可能通过这种图形界面来操作, 我们一般会通过solr为我们提供的API来操作solr进行分词操作.
java代码的实现:
- 添加和删除
package cn.itcast.solr;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.common.SolrInputDocument;
import org.junit.Test;
public class IndexManagerTest {
// 添加
@Test
public void testIndexCreate() throws Exception{
//创建和Solr服务端连接
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
//创建solr文档对象
SolrInputDocument doc = new SolrInputDocument();
//域要先定义后使用,还有注意必须要有id主键域
//solr中没有专用的修改方法, 会自动根据id进行查找,如果找到了则删除原来的将新的加入就是修改,如果没找到,将新的直接加入则就是新增
doc.addField("cust_id", 1);
doc.addField("cust_name", "张三");
doc.addField("cust_source", "湖南");
doc.addField("cust_industry", "前端开发工程狮");
//将文档加入solrServer对象中
solrServer.add(doc);
//提交
solrServer.commit();
}
// 删除
@Test
public void testIndexDel() throws Exception{
//创建和Solr服务端连接
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
//根据主键id进行删除
//solrServer.deleteById("a001");
//根据查询删除,这里是删除所有*:*
solrServer.deleteByQuery("*:*");
//提交
solrServer.commit();
}
}
- 查询操作
package cn.itcast.solr;
import java.util.List;
import java.util.Map;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.junit.Test;
public class IndexSearchTest {
@Test
public void testIndexSearch1() throws Exception{
//连接solr服务端
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
//创建solr查询条件对象
SolrQuery solrQuery = new SolrQuery();
//查询所有
solrQuery.setQuery("*:*");
//查询并获取查询响应对象
QueryResponse queryResponse = solrServer.query(solrQuery);
//从查询响应中获取查询结果集对象
SolrDocumentList results = queryResponse.getResults();
//打印一共查询到多少条记录,也就是记录总数
System.out.println("=====count====" + results.getNumFound());
//遍历查询结果集
for(SolrDocument doc : results){
System.out.println("============="+doc.get("cust_id"));
System.out.println("============="+doc.get("cust_name"));
System.out.println("============="+doc.get("cust_source"));
System.out.println("============="+doc.get("cust_industry"));
System.out.println("====================================================");
}
}
@Test
public void testIndexSearch2() throws Exception{
//连接solr服务端
SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
//创建solr查询条件对象
SolrQuery solrQuery = new SolrQuery();
//查询关键字输入
solrQuery.setQuery("张三");
//设置默认搜索域
solrQuery.set("df", "cust_name");
//设置过滤查询
solrQuery.addFilterQuery("cust_id:[1 TO 100]");
//设置排序,这里是降序
solrQuery.setSort("cust_id", ORDER.desc);
//=======设置分页========
//设置起始条数
solrQuery.setStart(0);
//设置查询多少条
solrQuery.setRows(50);
//========设置高亮显示=======
//高亮默认是关闭的,所以要手动开启
solrQuery.setHighlight(true);
//设置需要高亮显示的域
solrQuery.addHighlightField("cust_name");
//设置高亮前缀
solrQuery.setHighlightSimplePre("<span style=\"color:red\">");
//设置高亮后缀
solrQuery.setHighlightSimplePost("</span>");
//===================查询并获取查询响应对象=====================================
QueryResponse queryResponse = solrServer.query(solrQuery);
//从查询响应中获取查询结果集对象
SolrDocumentList results = queryResponse.getResults();
//打印一共查询到多少条记录,也就是记录总数
System.out.println("=====count====" + results.getNumFound());
//遍历查询结果集
for(SolrDocument doc : results){
System.out.println("============="+doc.get("cust_id"));
//获取高亮
Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
List<String> list = highlighting.get(doc.get("cust_id")).get("cust_name");
if(list != null && list.size() > 0){
String hlName = list.get(0);
System.out.println("=======high lighting=====" + hlName);
}
System.out.println("============="+doc.get("cust_name"));
System.out.println("============="+doc.get("cust_source"));
System.out.println("============="+doc.get("cust_industry"));
System.out.println("====================================================");
}
}
}