Solr的运行需要Java环境,需要部署到Servlet容器中,可以选择Jetty或Tomcat。Solr默认自带了Jetty容器,可以很轻松的完成部署。
以下将分别讲解如何在Jetty和Tomcat下完成Solr的部署。
部署前的准备工作
- 去JDK官网下载最新版本的JDK并安装
- 到solr官网下载最新版的solr,本文用的是solr-8.5.1.zip,解压后的内容如下图所示:
一. 在Jetty下部署Solr
进入bin目录,打开cmd,启动命令 solr start,默认端口 8983,启动时可以通过 -p 来指定端口号
如:solr start -p 6789,运行结果如下图所示:
然后打开浏览器,输入http://localhost:6789/solr 即可看到下图所示表示部署成功。
以下是几个常用的命令
// 启动solr
solr start -p 端口号
// 停止solr
solr stop -all
// 重启solr
solr restart -p 端口号
// 创建/删除一个core
solr create -c name
solr delete -c name
// 查看状态
solr status
二. 在Tomcat下部署Solr
1. 安装Tomcat
-
去官网下载最新版本的Tomcat并安装,本文用的是apache-tomcat-9.0.34.exe
-
安装完成后,访问localhost:8080,看到下图所示内容即表示安装成功
2. 部署Solr
-
将
solr-8.5.1\server\solr-webapp\webapp文件夹拷贝到在Tomcat 9.0\webapps\下并将文件夹重命名为solr -
配置solr_home
-
新建一个文件夹,做为solr_home,如
D:/solr_home -
拷贝
solr-8.5.1\server\solr文件夹下的所有文件到D:\solr_home下 -
修改
Tomcat 9.0\webapps\solr\WEB-INF\web.xml文件内容,在现有的<web-app>标签体内添加以下内容<env-entry> <env-entry-name>solr/home</env-entry-name> <env-entry-value>D:/solr_home</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry>
-
-
拷贝拷贝
solr-8.5.1\server\lib\和solr-8.5.1\server\lib\ext\下的所有jar包到Tomcat 9.0\webapps\solr\WEB-INF\lib\下 -
配置classes
- 新建文件夹classes,位置:
Tomcat 9.0\webapps\solr\WEB-INF\classes - 拷贝
solr-8.5.1\server\resources\jetty-logging.properties到classes文件夹下
- 新建文件夹classes,位置:
-
最后一步,就是将Tomcat 9.0\webapps\solr\WEB-INF\web.xml中的权限验证注释掉就行,即注释掉以下内容
<!-- <security-constraint> <web-resource-collection> <web-resource-name>Disable TRACE</web-resource-name> <url-pattern>/</url-pattern> <http-method>TRACE</http-method> </web-resource-collection> <auth-constraint/> </security-constraint> <security-constraint> <web-resource-collection> <web-resource-name>Enable everything but TRACE</web-resource-name> <url-pattern>/</url-pattern> <http-method-omission>TRACE</http-method-omission> </web-resource-collection> </security-constraint> -->/update/extract
-
至此便可以正常访问solr了,记得在tomcat里重新加载下solr,URL地址:localhost:8080/solr/index.html
三. 创建我的第一个索引
创建索引之前,需要先在solr home文件夹下先创建对应的文件夹,这里以C:\solr_home\为例
-
在solr_home文件夹下新建文件夹
my_first_core -
拷贝
C:\solr_home\configsets\_default\conf文件夹到my_first_core下 -
在solr页面中
Add Core -
创建成功后可以看到以下内容
四. 安装中文分词器
常用的中文分词器有2个:Smartcn和IKanalyzer
1. Smartcn
-
第一步:关联所需jar包
lucene-analyzers-smartcn-8.5.1.jar-
方式1:添加jar包的依赖路径(推荐) 修改solrconfig.xml文件,添加以下内容(其中相对路径是从solr_home文件夹开始拼接)
<lib path="../../../contrib/analysis-extras/lucene-libs/lucene-analyzers-smartcn-8.5.1.jar" /> -
方式2:将所依赖的jar包拷贝到WEB-INF\lib路径下
拷贝文件夹solr-8.5.1\contrib\analysis-extras\lucene-libs下的jar包到Tomcat 9.0\webapps\solr\WEB-INF\lib\下
-
-
第二步:编辑managed-schema文件,添加以下内容
<!-- 配置中文分词器 --> <fieldType name="text_smartcn" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/> </analyzer> </fieldType> -
第三步:重新加载solr服务器后进入Analyse页面,试下中文分词器的效果,如下图所示
2. IKanalyzer
查看Github主页的帮助文档进行安装配置即可
五. solrj的使用
以下用一个简单的示例来演示solrj的使用。配置3个字段,分别是:id、title和content
1. solr服务端字段配置(managed-schema)
在conf/managed-schema文件中添加以下内容,用以配置title和content字段(因为id字段默认已经含有,无需另外添加)
<field name="title" type="text_en" indexed="true" stored="true" multiValued="true"/>
<field name="content" type="text_en" indexed="true" stored="true" omitNorms="true" multiValued="false"/>
2. solrj客户端代码
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
public class CMySolrjTest {
final String SOLR_URL = "http://127.0.0.1:8080/solr/my_first_core";
public static void main(String[] args) {
CMySolrjTest test = new CMySolrjTest();
try {
//test.addDoc();
test.queryDoc();
//test.deleteDoc();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("运行结束");
}
public void addDoc() throws Exception {
SolrClient solrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(6000).build();
SolrInputDocument document = new SolrInputDocument();
document.addField("id", "ssx.txt");
document.addField("title", "This is my title-yaoyuliang");
document.addField("content", "This is my file content-yaoyuliang");
solrClient.add(document);
solrClient.commit();
}
public void queryDoc() throws Exception {
HttpSolrClient solrServer = new HttpSolrClient.Builder(SOLR_URL)
.withConnectionTimeout(10000)
.withSocketTimeout(60000)
.build();
SolrQuery query = new SolrQuery();
query.set("q", "content:yaoyuliang");
// 调用server的查询方法,查询索引库
QueryResponse response = solrServer.query(query);
// 查询结果
SolrDocumentList results = response.getResults();
// 查询结果总数
long cnt = results.getNumFound();
System.out.println("查询结果总数:" + cnt);
for (SolrDocument solrDocument : results) {
System.out.println(solrDocument.get("id"));
System.out.println(solrDocument.get("title"));
System.out.println(solrDocument.get("content"));
}
}
public void deleteDoc() throws Exception {
SolrClient solrClient=new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(6000).build();
//根据id删除
//solrClient.deleteById("005");
//根据查询条件删除
solrClient.deleteByQuery("*:*");
//提交
solrClient.commit();
}
}
六. 导入pdf/office等富文本文件
导入富文本的方式有2种,一种是客户端直接上传文件,交由服务器端进行解析。另一种是客户端解析好,上传至服务器。下面将分别介绍2种方式的使用。
1. 在服务器端进行富文本解析(不推荐)
1.1. 编辑solrconfig.xml文件,添加相关jar包的依赖。
<lib dir="../../lib" />
<lib dir="../../../dist" />
<lib dir="../../../contrib/extraction/lib" />
1.2. 编辑solrconfig.xml文件,添加requestHandler
<requestHandler name="/update/extract" class="solr.extraction.ExtractingRequestHandler" startup="lazy">
<lst name="defaults">
<str name="uprefix">ignored_</str>
</lst>
</requestHandler>
- requestHandler的各字段含义表
| 关键字 | 描述 |
|---|---|
| fmap.XXX | 映射,示例:fmap.content=text(将Tick生成的content字段映射到text) fmap.content 文件内容 fmap.stream_size 文件大小 fmap.stream_name 内容流的名称 fmap.stream_content_type 流的内容类型 |
| literal.XXX | 使用指定的值创建一个字段 |
| lowernames | 所有字段名称都将使用下划线映射为小写,如输入“ Content-Type”,则文档中的结果将是一个字段content_type |
| uprefix | 为没有在schema中定义的字段加一个统一的前缀。 示例: uprefix=ignored_为所有未知字段添加 ignored_前缀可以在schema中同时添加以下语句实现不索引未定义的这些字段 <dynamicField name="ignored_*" type="ignored" /> |
| captureAttr | 对属性进行索引,如从HTML提取时,Tika可以将标签中的href属性作为名为“ a”的字段返回 |
| commitWithin | 在指定的毫秒数内添加文档。示例:commitWithin=10000(10秒) |
| ignoreTikaException | 如果为true,则将跳过在处理期间发现的异常。但是,所有可用的元数据都会被索引 |
| multipartUploadLimitInKB | 定义要允许的文档大小(以千字节为单位)。默认值为2048(2Mb)。如果文档非常大,则应增加此文档,否则将被拒绝。 例: multipartUploadLimitInKB=2048000 |
1.3. 编辑managed-schema,添加文件内容字段(通过postman、或者web界面、或者直接编辑都行)
<field name="content" type="text_ik" uninvertible="false" indexed="true" stored="true"/>
1.4. java示例代码
// 添加指定的pdf文件入索引库
public void addPdf() throws Exception {
SolrClient client = new HttpSolrClient.Builder(SOLR_URL)
.withConnectionTimeout(10000)
.withSocketTimeout(6000)
.build();
ContentStreamUpdateRequest request = new ContentStreamUpdateRequest("/update/extract");
request.addFile(new File("c:/tmp/xxx.pdf"), "application/pdf");
request.setParam("literal.id", "c:/tmp/xxx.pdf");
request.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
client.request(request);
}
// 遍历C:/tmp文件夹下的所有文件,全部导入到solr中
public void createIndexFromDir() throws Exception {
File dir = new File("c:/tmp");
File[] fileList = dir.listFiles();
SolrClient client = new HttpSolrClient.Builder(SOLR_URL)
.withConnectionTimeout(10000).withSocketTimeout(6000).build();
ContentStreamUpdateRequest request;
// 遍历文件夹下所有文件
for(File file : fileList) {
if(!file.isDirectory()) {
request = new ContentStreamUpdateRequest("/update/extract");
request.addFile(file, getFileContentType(file.getAbsolutePath()));
request.setParam("literal.id", file.getAbsolutePath());
client.request(request);
System.out.println("push file" + file.getAbsolutePath());
}
}
client.commit();
}
private static String getFileContentType(String filename) {
String contentType = "";
String prefix = filename.substring(filename.lastIndexOf(".") + 1);
if (prefix.equals("pdf")) {
contentType = "application/pdf";
} else if (prefix.equals("txt") || prefix.equals("xml")) {
contentType = "text/plain";
} else if (prefix.equals("xlsx")) {
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
} else if (prefix.equals("doc")) {
contentType = "application/msword";
} else if (prefix.equals("xls")) {
contentType = "application/vnd.ms-excel";
} else if (prefix.equals("docx")) {
contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
} else if (prefix.equals("ppt")) {
contentType = "application/vnd.ms-powerpoint";
} else if (prefix.equals("pptx")) {
contentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
} else {
contentType = "othertype";
}
return contentType;
}
2. 在客户端进行富文本解析(推荐)
2.1. 编辑managed-schema,添加文件内容字段(通过postman、或者web界面、或者直接编辑都行)
<field name="content" type="text_ik" uninvertible="false" indexed="true" stored="true"/>
2.2. 将所依赖的jar包导入到客户端工程中去
具体哪些jar包还没来的急整理,大概是这些文件夹下的jar先全依赖上
dist文件夹下的
extraction文件夹下的
solr-8.5.1\server\lib\文件夹
commons-lang3-3.9.jar
需要额外下载的jar包
jai-imageio-core-1.4.0.jar 也可以去bintray.com下载其它版本,或去项目的Github主页下载。
jai-imageio-jpeg2000-1.3.0.jar 也可以去mvnrepository.com下载其它版本,或去项目的Github主页下载。
sqlite-jdbc-3.30.1.jar 也可以去mvnrepository.com下载其它版本。
2.3. Java示例代码
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;
public class CMySolrjTest {
final String SOLR_URL = "http://127.0.0.1:6789/solr/my_first_core/";
private AutoDetectParser autoParser;
HttpSolrClient client;
private Collection<SolrInputDocument> docList = new ArrayList<SolrInputDocument>();
private int totalTika = 0;
public void addByTika() throws Exception {
autoParser = new AutoDetectParser();
client = new HttpSolrClient.Builder(SOLR_URL)
.withConnectionTimeout(10000)
.withSocketTimeout(6000)
.build();
doTikaDocuments(new File("C:/tmp/"));
}
private void doTikaDocuments(File root) throws IOException, SolrServerException{
for (File file : root.listFiles()) {
if (file.isDirectory()) {
doTikaDocuments(file);
continue;
}
ContentHandler textHandler = new BodyContentHandler();
Metadata metadata = new Metadata();
ParseContext context = new ParseContext();
InputStream input = new FileInputStream(file);
try {
autoParser.parse(input, textHandler, metadata, context);
}
catch (Exception e) {
System.out.println(String.format("File %s failed", file.getCanonicalPath()));
e.printStackTrace();
continue;
}
//dumpMetadata(file.getCanonicalPath(), metadata);
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", file.getCanonicalPath());
doc.addField("content", textHandler.toString());
docList.add(doc);
++totalTika;
//if (docList.size() >= 1000) {
UpdateResponse resp = client.add(docList, 300000);
if (resp.getStatus() != 0) {
System.out.println("Some horrible error has occurred, status is: " + resp.getStatus());
}
docList.clear();
//}
client.commit();
}
}
private void dumpMetadata(String fileName, Metadata metadata) {
System.out.println("Dumping metadata for file: " + fileName);
for (String name : metadata.names()) {
System.out.println(" " + name + ":" + metadata.get(name));
}
}
}
七. DataImport问题
- 拷贝solr-8.5.1\dist下的jar包到Tomcat 9.0\webapps\solr\WEB-INF\lib\下
主要是拷这2个jar包文件
solr-dataimporthandler-8.5.1.jar
solr-dataimporthandler-extras-8.5.1.jar
- 修改solrconfig.xml指向数据描述文件
<requestHandler name="/dataimport" class="solr.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
- 添加文件data-config.xml的内容如下:
<dataConfig>
<dataSource name="fileDataSource" type="FileDataSource" />
<!--<document>
<entity name="tika-test" processor="TikaEntityProcessor"
url="C:/docs/solr-word.pdf" format="text">
<field column="Author" name="author" meta="true"/>
<field column="title" name="title" meta="true"/>
<field column="text" name="text"/>
</entity>
</document>-->
<dataSource name="urlDataSource" type="BinURLDataSource" />
<!--baseDir="D:/work/Solr/solr-6.6.0/ImportDoc" fileName=".*\.(doc)|(pdf)|(docx)|(txt)"-->
<document>
<entity name="files" dataSource="null" rootEntity="false"
processor="FileListEntityProcessor"
baseDir="D:/work/Solr/solr-6.6.0/ImportDoc" fileName=".*\.(json)|(txt)|(csv)|(xml)"
onError="skip"
recursive="true">
<field column="file" name="id"/>
<field column="fileAbsolutePath" name="filePath" />
<field column="fileSize" name="size" />
<field column="fileLastModified" name="lastModified" />
<entity processor="PlainTextEntityProcessor" name="txtfile" url="${files.fileAbsolutePath}" dataSource="fileDataSource">
<field column="plainText" name="text"/>
</entity>
</entity>
</document>
</dataConfig>
八. 各配置文件的作用
- managed-schema:定义了索引数据类型,索引字段等信息。老版本的schema配置文件是schema.xml,它的编辑方式是手动编辑,而managed-schema的编辑方式是通过Schema API来配置
- uniqueKey:文档的唯一标示,相当于主键,每次更新,删除的时候都根据这个字段来进行操作
- fieldtype
- 定义数据类型
- 定义当前类型建立索引和查询数据的时候使用的查询分词器
- field:指定建立索引和查询数据的字段
- dynamicField:动态定义一个字段,只要符合规则的字段都可以
<dynamicField name="*_i" stored="true" indexed="true" type="int"/>
*_i 只要以_i结尾的字段都满足这个定义。
- copyField:把一个字段的值复制到另一个字段中,这样搜索的时候都可以根据一个字段来进行搜索
- solrconfig.xml:定义了Solr的一些处理规则,包括索引数据的存放位置,更新,删除,查询的一些规则配置
- luceneMatchVersion:表示solr底层使用的是lucene版本
- lib:表示solr引用包的位置,当dir对应的目录不存在时候,会忽略此属性
- datadDir:定义了索引数据和日志文件的存放位置
- directoryFactory:索引存储方案
- codecFactory:指定编码、解码器
- indexConfig:设置索引的低级别的属性
- updateHandler
- updateLog:设置索引库更新日志
- autoCommit:设置自动硬提交方式
- query:设置查询相关参数
- requestHandler:solr请求转发器
- requestHandler:solr请求映射处理器
Schema API操作managed-schema
准备工具Postman
-
add-field
效果就是在文件中添加了以下内容:<field name="sell_by" type="text_en" indexed="true" stored="true"/> -
delete-field
- 更多API操作参见官方schema-api手册
Solr查询URL
- 查询所有
http://localhost:8080/solr/primary/select?q=*:* - 限定返回字段(如查询所有,只返回productId字段)
http://localhost:8080/solr/primary/select?q=*:*&fl=productId - 查询前六条记录,只返回productId字段
http://localhost:8080/solr/primary/select?q=*:*&fl=productId&rows=6&start=0 - q - 查询字符串,必须的。
- fl - 指定返回那些字段内容,用逗号或空格分隔多个。
- start - 返回第一条记录在完整找到结果中的偏移位置,0开始,一般分页用。
- rows - 指定返回结果最多有多少条记录,配合start来实现分页。
- sort - 排序,格式:sort=+<desc|asc>[,+<desc|asc>]。示例:(inStock desc, price asc)表示先 "inStock" 降序, 再 "price" 升序,默认是相关性降序。
- wt - (writer type)指定输出格式,可以有 xml, json, php, phps。
附
运行jar文件,并指定依赖的包的路径,多个路径使用冒号":"分割
java -jar -Djava.ext.dirs=./ xxx.jar
date: 2020 年 04月 24日
参考文档:
[1] Solr中文网
[2] SolrJ8.5.1-官方API文档
[3] CSDN:通过solrj对solr进行开发
[4] CSDN: Solr 7.5.0 windows单机版
[5] Solr Ref Guide 8.5
[6] Uploading Data with Solr Cell using Apache Tika
[7] Indexing Existing Data with SolrJ in Apache Solr