主题
以前的部署日志
初始化
通过docker 部署及创建登录用户
sh
# 通过docker部署solr并创建登录用户,同时挂载卷用于映射本地文件夹到容器内部
docker run --name solr -p 8983:8983 -d --restart=always -v /data/solr/custom-lib:/opt/solr-8.4.1/server/solr-webapp/webapp/WEB-INF/lib -v /data/solr/conf:/var/solr/data/problem/conf -v /data/solr/classes:/opt/solr-8.4.1/server/solr-webapp/webapp/WEB-INF/classes solr
docker exec -it --user=solr solr bin/solr create_core -c problem
ik分词器
从 IK Analyzer Solr的Maven仓库地址 下载jar包,放置到本地/data/solr/custom-lib目录下,容器会自动映射,无需手动拷贝。同样将ik配置文件放置到本地/data/solr/classes目录下,容器也会自动映射。
修改managed-schema文件,直接在本地/data/solr/conf目录下进行编辑,编辑完成后容器会自动更新,内容如下:
xml
#文件最下加入….
<fieldType name="text_ik" class="solr.TextField">
<analyzer type="index">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" />
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
配置solr登录密码
在容器内部进行配置:
sh
docker exec -it --user root solr /bin/bash
cd /opt/solr/server/etc
vi verify.properties
#写入
#用户名 密码 权限
#iksolr:ik3423,admin
# 生成加密的密码
java -cp /opt/solr-8.4.1/server/lib/jetty-util-9.4.19.v20190610.jar org.eclipse.jetty.util.security.Password iksolr ik3423
# 得到加密后的应该为
# 用户名 密码 权限
# iksolr:MD5:87a3ed00e309efd07a5f9c2629ebdf22,admin
对solr-jetty-context.xml文件进行配置:
sh
docker cp solr:/opt/solr/server/contexts/ solr-jetty-context.xml /data/solr
xml
<Get name="securityHandler">
<Set name="loginService">
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">verify—name</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/verify.properties</Set>
</New>
</Set>
</Get>
最后,将修改后的文件拷贝回容器:
sh
docker cp /data/solr/solr-jetty-context.xml solr:/opt/solr/server/contexts
docker cp solr:/opt/solr-8.4.1/server/solr-webapp/webapp/WEB-INF/web.xml /data/solr
注释web.xml
中的security-constraint
部分。
java 使用
java
/**
* @author hjh
* @version 1.0
* @date 2020/2/17 15:28
*/
@Component
public class SolrSevcie {
@Autowired
private HttpSolrClient client;
/**
* 添加或更新
*
* @param bean
*/
public <T> boolean save(T bean) throws Exception {
SolrInputDocument document = new SolrInputDocument();
Class cla = bean.getClass();
Field[] fields = cla.getDeclaredFields();
for (Field field : fields) {
//获取属性的名字
String name = field.getName();
//将属性的首字符大写,方便构造get,set方法
name = name.substring(0, 1).toUpperCase() + name.substring(1);
Method m = cla.getMethod("get" + name);
String value = (String) m.invoke(bean);
document.addField(field.getName(), value);
}
client.add(document);
UpdateResponse result = client.commit();
return result.getStatus() == 0;
}
/**
* 通过文档ID删除Solr中的文档
*
* @param id
*/
public boolean deleteById(String id) {
try {
client.deleteById(id);
UpdateResponse resp = client.commit();
return resp.getStatus() == 0;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 封装过的搜索
*
* @param searchStr 要搜索的内容
* @param page 开始页数
* @param limit 每页显示条数
* @return
*/
public PageBean<List<SolrBean>> querySimple(String searchStr, int page, int limit) {
return this.query("item_title:" + searchStr, (page - 1) * limit, limit, SolrBean.class);
}
/**
* 封装过的搜索
*
* @param searchStr 要搜索的内容
* @param page 开始页数
* @param limit 每页显示条数
* @return
*/
public PageBean<List<SolrBean>> queryHighlightSimple(String searchStr, int page, int limit) {
return this.baseQuery("item_title:" + searchStr, (page - 1) * limit, limit, "item_title", SolrBean.class);
}
/**
* 调用solr搜索(普通搜索)
*
* @param keywords
* @param start 从哪行开始
* @param limit 每页显示条数
* @param cla
* @param <T>
* @return
*/
protected <T> PageBean<List<T>> query(String keywords, int start, int limit, Class<T> cla) {
return this.baseQuery(keywords, start, limit, null, cla);
}
/**
* 自动提示
* @param value
* @return
*/
public PageBean<List<SolrBean>> term(String value) {
List<String> str = this.term("item_title", value);
if (Is.isNoEmpty(str)) {
List<SolrBean> list = new ArrayList<>();
str.forEach(p -> {
SolrBean solrBean = new SolrBean();
solrBean.setItem_title(p);
list.add(solrBean);
});
PageBean pageBean = new PageBean();
pageBean.setTotal(Long.valueOf(list.size()));
pageBean.setRows(list);
return pageBean;
}
return null;
}
/**
* 自动提示
* @param termField
* @param value
* @return
*/
private List<String> term(String termField, String value) {
SolrQuery query = new SolrQuery();
// 不要结果集!!!
query.setStart(0);
query.setRows(0);
// 该字段已在sole配置
query.setQuery(termField + ":" + value);
// 提词
query.setTerms(true);
// 最多返回10条
query.setTermsLimit(10);
// 可选的. 设置最小统计个数
query.setTermsMinCount(1);
// query.setTermsMaxCount(10);
// query.setTermsRaw(true);
// 可选的. 这个term开始。如果不指定,使用空字符串,这意味着从头开始的。
// 效率更高!!!
query.setTermsLower(value);
// 可选的. 限制匹配,设置terms前缀是以什么开始的。
query.setTermsPrefix(value);
// 词频最高排序
query.setTermsSortString("count");
query.addTermsField(termField);
try {
QueryResponse result = client.query(query);
if (result.getStatus() == 0) {
TermsResponse termsResponse = result.getTermsResponse();
Map<String, List<TermsResponse.Term>> map = termsResponse.getTermMap();
List<TermsResponse.Term> list = map.get(termField);
if (Is.isNoEmpty(list)) {
ArrayList<String> strs = new ArrayList<>();
list.forEach(l -> {
strs.add(l.getTerm());
});
return strs;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 调用solr搜索
*
* @param keywords
* @param start
* @param limit
* @param hlField
* @param cla
* @param <T>
* @return
*/
private <T> PageBean<List<T>> baseQuery(String keywords, int start, int limit, String hlField, Class<T> cla) {
SolrQuery query = new SolrQuery();
query.setStart(start);
query.setRows(limit);
// 该字段已在sole配置
query.setQuery(keywords);
query.addSort("score", SolrQuery.ORDER.desc);
query.setParam("q.op", "and");
// 高亮
boolean hlFlag = Is.isNoEmpty(hlField);
if (hlFlag) {
// 开启高亮
query.setHighlight(true);
// 高亮字段
query.addHighlightField(hlField);
// 高亮单词的前缀
query.setHighlightSimplePre("<font style='color:red'>");
// 高亮单词的后缀
query.setHighlightSimplePost("</font>");
//摘要最长1000个字符
query.setHighlightFragsize(500);
query.setSort("item_type", SolrQuery.ORDER.desc);
}
try {
QueryResponse result = client.query(query);
if (result.getStatus() == 0) {
//[5]遍历结果
// TermsResponse termsResponse = result.getTermsResponse();
// List<TermsResponse.Term> terms = termsResponse.getTerms("p_name");
// for (TermsResponse.Term term : terms) {
// System.out.println(term.getTerm() + ":\t"+ term.getFrequency());
// }
SolrDocumentList list = result.getResults();
// 总条数
Long total = list.getNumFound();
List<T> tList = new ArrayList<>();
for (SolrDocument p : list) {
try {
T t = cla.newInstance();
Collection<String> collection = p.getFieldNames();
for (String c : collection) {
// 判断有没有这个属性
if (!"_version_".equals(c) && cla.getDeclaredField(c) != null) {
//将属性的首字符大写,方便构造get,set方法
String name = c.substring(0, 1).toUpperCase() + c.substring(1);
System.out.print("set" + name);
Method m = cla.getMethod("set" + name, new Class[]{String.class});
m.invoke(t, (String) p.get(c));
}
}
if (hlFlag) {
//获取高亮字段name相应结果
NamedList<Object> response = result.getResponse();
//获取高亮字段name相应结果
NamedList<SimpleOrderedMap> highlighting = (NamedList<SimpleOrderedMap>) response.get("highlighting");
// 循环结果集,判断id
for (int i = 0; i < highlighting.size(); i++) {
String id = (String) cla.getMethod("getId").invoke(t);
// 判断id相等
if (highlighting.getName(i).equals(id)) {
SimpleOrderedMap map = highlighting.getVal(i);
ArrayList temp = (ArrayList) map.get(hlField);
if (Is.isNoEmpty(temp)) {
// 替换字符串
String val = (String) temp.get(0);
String name = hlField.substring(0, 1).toUpperCase() + hlField.substring(1);
cla.getMethod("set" + name, new Class[]{String.class}).invoke(t, val);
}
break;
}
}
}
tList.add(t);
} catch (Exception e) {
e.printStackTrace();
}
}
PageBean pageBean = new PageBean();
pageBean.setTotal(total);
pageBean.setRows(tList);
return pageBean;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
java
package com.ciw.main.solr;
import lombok.Data;
/**
* solrj操作对象, 需先在solr里面配置对应的字段
* @author hjh
* @version 1.0
* @date 2020/2/17 15:14
*/
@Data
public class SolrBean {
/**
* 唯一标识
*/
private String id;
/**
* 要搜索的内容
*/
private String item_title;
/**
* 用于区分是搜索什么
*/
private String item_type;
/**
* 需要使用到的json数据
*/
private String item_data;
}
java
/**
* @author hjh
* @version 1.0
* @date 2020/2/16 19:00
*/
@Configuration
public class SolrConfig {
@Value("${spring.data.solr.url:}")
private String url;
@Value("${spring.data.solr.host:}")
private String host;
@Value("${spring.data.solr.port:}")
private Integer port;
@Value("${spring.data.solr.user:}")
private String user;
@Value("${spring.data.solr.pwd:}")
private String pwd;
public class SolrAuthInterceptor implements HttpRequestInterceptor {
@Override
public void process(final HttpRequest request, final HttpContext context) {
AuthState authState = (AuthState) context.getAttribute(HttpClientContext.TARGET_AUTH_STATE);
if (authState.getAuthScheme() == null) {
CredentialsProvider credsProvider =
(CredentialsProvider) context.getAttribute(HttpClientContext.CREDS_PROVIDER);
HttpHost targetHost = (HttpHost) context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST);
AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
Credentials creds = credsProvider.getCredentials(authScope);
authState.update(new BasicScheme(), creds);
}
}
}
@Bean
public HttpSolrClient solrClient() {
CredentialsProvider provider = new BasicCredentialsProvider();
provider.setCredentials(new AuthScope(host, port),
new UsernamePasswordCredentials(user, pwd));
HttpClientBuilder builder = HttpClientBuilder.create();
// 请注意下面这一行,指定拦截器,用于设置认证信息
builder.addInterceptorFirst(new SolrAuthInterceptor());
builder.setDefaultCredentialsProvider(provider);
CloseableHttpClient httpClient = builder.build();
return new HttpSolrClient.Builder(url + "/problem").withHttpClient(httpClient).build();
}
}
xml
<dependency>
<groupId>solr</groupId>
<artifactId>solr</artifactId>
<version>8.4.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/solr-solrj-8.4.1.jar</systemPath>
</dependency>