在上文中我们已经详细介绍了 Solr 的部署 ,本文我们将介绍 Solr 在 Java 中的使用。
上文传送门 :
[Solr] Apache Solr 简介及使用
[Solr] Apache Solr 集群
索引库 schema.xml 配置文件
<schema name="example" version="1.5">
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="_root_" type="string" indexed="true" stored="false"/>
<field name="id" type="string" indexed="true"
stored="true" required="true" multiValued="false" />
<field name="name" type="text_ws" indexed="true" stored="true"/>
<field name="price" type="float" indexed="true" stored="true"/>
<field name="title" type="text_ws" indexed="true" stored="true" multiValued="false"/>
<field name="content" type="text_ws" indexed="true" stored="true" multiValued="false"/>
<field name="text" type="text_ws" indexed="true" stored="true" multiValued="true"/>
<field name="date" type="date" indexed="true" stored="true"/>
<field name="binary" type="binary" indexed="true" stored="true"/>
<dynamicField name="*_ss" type="string" indexed="true"
stored="true" multiValued="true"/>
<uniqueKey>iduniqueKey>
<copyField source="title" dest="text"/>
<copyField source="content" dest="text"/>
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>
<fieldType name="int" class="solr.TrieIntField"
precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField"
precisionStep="0" positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField"
precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField"
precisionStep="0" positionIncrementGap="0"/>
<fieldType name="date" class="solr.TrieDateField"
precisionStep="0" positionIncrementGap="0"/>
<fieldtype name="binary" class="solr.BinaryField"/>
<fieldType name="text_ws" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
fieldType>
schema>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
<dependency>
<groupId>org.apache.solrgroupId>
<artifactId>solr-solrjartifactId>
<version>4.10.2version>
dependency>
<dependency>
<groupId>commons-logginggroupId>
<artifactId>commons-logging-apiartifactId>
<version>1.1version>
dependency>
private static String URL = "http://hadoop1:8080/solr/collection3";
private static SolrServer solrServer =
new HttpSolrServer(URL);
创建一个文档
@Test
public void addSolrDoc () throws IOException, SolrServerException {
SolrInputDocument document = new SolrInputDocument();
// 设置激励因子,默认是1
document.setDocumentBoost(1);
document.addField("id", "1");
document.addField("title","媲美故宫的“铜宫”");
document.addField("content","雷峰塔、峨眉金顶、灵隐铜殿," +
"上百件标志性铜建筑让他成为“中国当代铜建筑之父”," +
"他是中国铜雕领域界唯一一位国家级非遗传承人");
document.addField("date",new Date());
document.addField("binary","solr".getBytes());
solrServer.add(document);
solrServer.commit();
}
注 :
1 > 在Solr中,一个Document必须包含ID,因为Solr是根据ID维护Document的
2 > 一个Fiele中的name值必须是schema.xml中存在的field,如果不存在该Field,会报错
创建多个文档
@Test
public void addSolrDocs() throws IOException, SolrServerException {
ArrayList documents = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
SolrInputDocument document = new SolrInputDocument();
// 设置激励因子,默认是1
document.setDocumentBoost(1);
document.addField("id", i+"");
document.addField("title", "媲美故宫的“铜宫”");
document.addField("content", "雷峰塔、峨眉金顶、灵隐铜殿," +
"上百件标志性铜建筑让他成为“中国当代铜建筑之父”," +
"他是中国铜雕领域界唯一一位国家级非遗传承人");
document.addField("date", new Date());
document.addField("binary", "solr".getBytes());
documents.add(document);
}
solrServer.add(documents);
solrServer.commit();
}
其实Solr在修改时,做的依旧是add操作,只不过Solr会根据document的ID来查询此document是否存在,如果存在,会先删除此document,然后执行add操作。
@Test
public void updateSolrDoc () throws IOException, SolrServerException {
SolrInputDocument document = new SolrInputDocument();
// 设置激励因子,默认是1
document.setDocumentBoost(1);
document.addField("id", 10);
document.addField("title", "媲美故宫的“铜宫”");
document.addField("content", "这是修改后的内容");
solrServer.add(document);
solrServer.commit();
}
由于上面我们已经批量添加了10条数据,我们执行完修改操作后,在来看看ID为10的Document,发现该Document的date与binary都消息了,证明先执行了删除,后执行了新增。
{
"id": "10",
"title": "媲美故宫的“铜宫”",
"text": [
"媲美故宫的“铜宫”",
"这是修改后的内容"
],
"content": "这是修改后的内容",
"_version_": 1608276634333347800
}
注 : 在JavaBean中要对字段加上 @Field 注解,才能被Solr识别
public class SolrDocument {
@Field
private String id;
@Field
private String name;
@Field
private double price;
@Field
private String title;
@Field
private String content;
@Field
private ArrayList text;
@Field
private Date date;
@Field
private byte[] binary;
//... get set
}
@Test
public void addSolrBean() throws IOException, SolrServerException {
SolrDocument solrDocument = new SolrDocument();
solrDocument.setId("11");
solrDocument.setTitle("媲美故宫的“铜宫”");
solrDocument.setContent("雷峰塔、峨眉金顶、灵隐铜殿," +
"上百件标志性铜建筑让他成为“中国当代铜建筑之父”," +
"他是中国铜雕领域界唯一一位国家级非遗传承人");
solrDocument.setDate(new Date());
solrDocument.setBinary("solr".getBytes());
solrServer.addBean(solrDocument);
solrServer.commit();
}
/**
* 删除单个Doc
*/
@Test
public void deleteDocById () throws IOException, SolrServerException {
solrServer.deleteById("11");
solrServer.commit();
}
/**
* 删除多个Doc
*/
@Test
public void deleteDocByIds () throws IOException, SolrServerException {
List ids = new ArrayList<>();
ids.add("9");
ids.add("10");
solrServer.deleteById(ids);
solrServer.commit();
}
/**
* 根据查询条件删除
*/
@Test
public void deleteAll() throws IOException, SolrServerException {
// *:* 删除所有doc
solrServer.deleteByQuery("*:*");
solrServer.commit();
}
/**
* 查询所有DOC,返回Results
*/
@Test
public void selectByDoc () throws SolrServerException {
SolrQuery query = new SolrQuery("*:*");
QueryResponse response = solrServer.query(query);
SolrDocumentList results = response.getResults();
for (org.apache.solr.common.SolrDocument result : results) {
String id = (String) result.getFieldValue("id");
Double price = (Double) result.getFieldValue("price");
Collection
/**
* 通配符查询
* ? : 占位符,表示占用一个字符
* * :占位符,表示占用0到多个字符
*/
@Test
public void wildSelect () throws SolrServerException {
SolrQuery query = new SolrQuery("content:雷峰?");
selectByQuery(query);
query = new SolrQuery("content:雷峰*");
selectByQuery(query);
}
/**
* 模糊查询 : 需要在查询的值后面加上~符号
*/
@Test
public void fuzzSelect () throws SolrServerException {
// 如果不加后面的2,默认就是移位两次
SolrQuery query = new SolrQuery("content:塔雷峰~2");
selectByQuery(query);
// 为了避免用户在输入的值上也输入~,可以将用户输入的值用双引括起来
query = new SolrQuery("content:\"塔雷峰\"~2");
selectByQuery(query);
query = new SolrQuery("content:\"雷峰~\"~2");
selectByQuery(query);
}
/**
* 范围查询
* 语法格式 :
* 1> field:[start TO end] (包含边界值)
* 2> field:{start TO end} (不包含边界值)
*/
@Test
public void rangeSelect () throws SolrServerException {
// 查询 1、2
SolrQuery query = new SolrQuery("price:[1 TO 2]");
selectByQuery(query);
// 查询 1、2,没有3
query = new SolrQuery("price:[1 TO 3}");
selectByQuery(query);
}
注 : 排序的字段最好是数值类型,日期类型等,否则排序出来的结果可能差强人意
/**
* 组合查询 : 可以将多个表达式组合起来一起查询
* 使用 : AND NOT OR 即可
*
* AND : 此条件必须包含
* NOT : 不能包含此条件里的内容
* OR : 可选的,如果有就返回,没有就不管
*/
@Test
public void booleanSelect () throws SolrServerException {
String term = "price:[1 TO 5] NOT id:1 OR id:8 OR content:\"塔雷峰\"~2";
SolrQuery query = new SolrQuery(term);
selectByQuery(query);
}
/**
* SolrQuery#setSort : [asc|desc]
*/
@Test
public void sortSelect () throws SolrServerException {
SolrQuery query = new SolrQuery("*:*");
query.setSort("price", SolrQuery.ORDER.asc);
selectByQuery(query);
}
/**
* 分页查询 :
* SolrQuery#setStart : 起始点
* SolrQuery#setRows : 查询条数
*/
@Test
public void pageSelect () throws SolrServerException {
SolrQuery query = new SolrQuery("*:*");
// 从第一条开始查
query.setStart(0);
// 共查3条
query.setRows(3);
selectByQuery(query);
}
/**
* 高亮查询
*/
@Test
public void highSelect() throws SolrServerException {
SolrQuery query = new SolrQuery("content:雷峰塔");
query.setHighlight(true);
//设置高亮字段,可设置多个
query.addHighlightField("content");
query.addHighlightField("title");
//设置前缀后缀
query.setHighlightSimplePre("");
query.setHighlightSimplePost("");
//设置高亮分片,默认是1
query.setHighlightSnippets(1);
//高亮之前的结果
QueryResponse response = solrServer.query(query);
List documents = response.getBeans(SolrDocument.class);
for (SolrDocument document : documents) {
System.out.println(document);
}
//高亮之后的结果
Map>> highlighting =
response.getHighlighting();
for (String docId : highlighting.keySet()) {
System.out.println("Document ID : " + docId);
Map> stringListMap = highlighting.get(docId);
for (String field : stringListMap.keySet()) {
System.out.println("Document field" + field);
List stringList = stringListMap.get(field);
System.out.println("高亮之后 : " + stringList);
}
}
}
<field name="text" type="text_ws" indexed="true" stored="true" multiValued="true"/>
<copyField source="title" dest="text"/>
<copyField source="content" dest="text"/>
1 引入依赖
<dependency>
<groupId>org.springframework.datagroupId>
<artifactId>spring-data-solrartifactId>
<version>1.5.5.RELEASEversion>
dependency>
2 创建spring-solr.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:solr="http://www.springframework.org/schema/data/solr"
xsi:schemaLocation="
http://www.springframework.org/schema/data/solr
http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<solr:solr-server id="solrServer"
url="http://192.168.211.133:8080/solr/collection1" />
<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">
<constructor-arg ref="solrServer" />
bean>
beans>
3 Field注解
public class TbItem implements Serializable{
@Field
private Long id;
@Field("item_title")
private String title;
@Field("item_price")
private BigDecimal price;
@Field("item_image")
private String image;
@Field("item_goodsid")
private Long goodsId;
@Field("item_category")
private String category;
@Field("item_brand")
private String brand;
@Field("item_seller")
private String seller;
//动态域
@Dynamic
@Field("item_spec_*")
private Map specMap;
//get set...
}
4 schema.xml
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
fieldType>
<field name="id" type="string"
indexed="true" stored="true" required="true" multiValued="false" />
<field name="item_goodsid" type="long" indexed="true" stored="true"/>
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="double" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category" type="string" indexed="true" stored="true" />
<field name="item_seller" type="text_ik" indexed="true" stored="true" />
<field name="item_brand" type="string" indexed="true" stored="true" />
<field name="item_keywords" type="text_ik"
indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_category" dest="item_keywords"/>
<copyField source="item_seller" dest="item_keywords"/>
<copyField source="item_brand" dest="item_keywords"/>
<dynamicField name="item_spec_*" type="string"
indexed="true" stored="true" />
新增
@Autowired
private SolrTemplate solrTemplate;
@Test
public void testAdd(){
TbItem item=new TbItem();
item.setId(1L);
item.setBrand("华为");
item.setCategory("手机");
item.setGoodsId(1L);
item.setSeller("华为2号专卖店");
item.setTitle("华为Mate9");
item.setPrice(new BigDecimal(2000));
solrTemplate.saveBean(item);
solrTemplate.commit();
}
新增集合
@Test
public void testAddList(){
List list=new ArrayList();
for(int i=0;i<100;i++){
TbItem item=new TbItem();
item.setId(i+1L);
item.setBrand("华为");
item.setCategory("手机");
item.setGoodsId(1L);
item.setSeller("华为2号专卖店");
item.setTitle("华为Mate"+i);
item.setPrice(new BigDecimal(2000+i));
list.add(item);
}
solrTemplate.saveBeans(list);
solrTemplate.commit();
}
查询
@Test
public void testFindOne(){
TbItem item = solrTemplate.getById(1, TbItem.class);
System.out.println(item.getTitle());
}
分页查询
@Test
public void testPageQuery(){
Query query=new SimpleQuery("*:*");
query.setOffset(20);//开始索引(默认0)
query.setRows(20);//每页记录数(默认10)
ScoredPage page = solrTemplate.queryForPage(query, TbItem.class);
System.out.println("总记录数:"+page.getTotalElements());
List list = page.getContent();
showList(list);
}
//显示记录数据
private void showList(List list){
for(TbItem item:list){
System.out.println(item.getTitle() +item.getPrice());
}
}
条件查询
注 : 注意条件查询时一定要用criteria重新接收一次值的引用
@Test
public void testPageQueryMutil(){
Query query=new SimpleQuery("*:*");
Criteria criteria=new Criteria("item_title").contains("2");
//注意下面这里一定要用criteria重新接收一次值的引用
//否则下面这个条件不会生效
criteria=criteria.and("item_title").contains("5");
query.addCriteria(criteria);
//query.setOffset(20);//开始索引(默认0)
//query.setRows(20);//每页记录数(默认10)
ScoredPage page = solrTemplate.queryForPage(query, TbItem.class);
System.out.println("总记录数:"+page.getTotalElements());
List list = page.getContent();
showList(list);
}
删除全部数据
@Test
public void testDeleteAll(){
Query query=new SimpleQuery("*:*");
solrTemplate.delete(query);
solrTemplate.commit();
}
分组查询
@Autowired
private SolrTemplate solrTemplate;
//将查询出来的结果按照 item_category 字段进行分组
private List<String> searchCategroyByKeyWords(Map map) {
List<String> result = new ArrayList<>();
Query query = new SimpleQuery();
//设置条件
Criteria criteria = new Criteria("item_keywords").is(map.get("keywords"));
query.addCriteria(criteria);
//设置分组
GroupOptions groupOptions = new GroupOptions().addGroupByField("item_category");
query.setGroupOptions(groupOptions);
GroupPage<TbItem> groupPage = solrTemplate.queryForGroupPage(query, TbItem.class);
//获取结果集
GroupResult<TbItem> groupResult = groupPage.getGroupResult("item_category");
Page<GroupEntry<TbItem>> groupEntries = groupResult.getGroupEntries();
List<GroupEntry<TbItem>> content = groupEntries.getContent();
for (GroupEntry<TbItem> tbItemGroupEntry : content) {
result.add(tbItemGroupEntry.getGroupValue());
}
return result;
}
多字段分组查询
//将查询出来的结果分别按照 item_category、item_brand 字段进行分组
private List searchCategroyByKeyWords(Map map) {
List result = new ArrayList<>();
List categoryList = new ArrayList<>();
List brandList = new ArrayList<>();
Query query = new SimpleQuery();
//设置条件
Criteria criteria = new Criteria("item_keywords").is(map.get("keywords"));
query.addCriteria(criteria);
//设置分组
GroupOptions groupOptions = new GroupOptions()
.addGroupByField("item_category").addGroupByField("item_brand");
query.setGroupOptions(groupOptions);
GroupPage groupPage = solrTemplate.queryForGroupPage(query, TbItem.class);
//获取 item_category 分组结果集
GroupResult groupResult = groupPage.getGroupResult("item_category");
Page> groupEntries = groupResult.getGroupEntries();
List> content = groupEntries.getContent();
for (GroupEntry tbItemGroupEntry : content) {
result.add(tbItemGroupEntry.getGroupValue());
categoryList.add(tbItemGroupEntry.getGroupValue());
}
//获取 item_brand 分组结果集
groupResult = groupPage.getGroupResult("item_brand");
groupEntries = groupResult.getGroupEntries();
content = groupEntries.getContent();
for (GroupEntry tbItemGroupEntry : content) {
result.add(tbItemGroupEntry.getGroupValue());
brandList.add(tbItemGroupEntry.getGroupValue());
}
System.out.println("categoryList"+categoryList);
System.out.println("brandList"+brandList);
System.out.println("result"+result);
/*
categoryList[手机, 平板电视, 内存, 电子书]
brandList[三星, 联想, 酷派]
result[手机, 平板电视, 内存, 电子书, 三星, 联想, 酷派]
*/
return result;
}
综合运用 : 高亮、Filter过滤查询、分页、排序
/**
* 设置高亮、Filter过滤查询、分页、排序
* @param map
* @return
*/
private Map hightSearch(Map map) {
Map result = new HashMap();
HighlightQuery query = new SimpleHighlightQuery();
//设置高亮
HighlightOptions highlightOptions = new HighlightOptions();
highlightOptions.addField("item_title");
highlightOptions.setSimplePrefix("");
highlightOptions.setSimplePostfix("");
query.setHighlightOptions(highlightOptions);
//查询条件
String keywords = (String) map.get("keywords");
Criteria criteria = new Criteria("item_title").is(keywords.replace(" ",""));
query.addCriteria(criteria);
//过滤条件
if (map.get("category") != null && !map.get("category").equals("")) {
FilterQuery filterQuery = new SimpleFilterQuery();
filterQuery.addCriteria(
new Criteria("item_category").is(map.get("category")));
query.addFilterQuery(filterQuery);
}
if (map.get("brand") != null && !map.get("brand").equals("")) {
FilterQuery filterQuery = new SimpleFilterQuery();
filterQuery.
addCriteria(new Criteria("item_brand").is(map.get("brand")));
query.addFilterQuery(filterQuery);
}
Map spec = (Map) map.get("spec");
if (spec != null && spec.size() > 0) {
for (String key : spec.keySet()) {
String value = spec.get(key);
FilterQuery filterQuery = new SimpleFilterQuery();
filterQuery.addCriteria(new Criteria("item_spec_" + key).is(value));
query.addFilterQuery(filterQuery);
}
}
//价格过滤
String price = (String) map.get("price");
if (price != null && !"".equals(price.trim())) {
String[] split = price.split("-");
if ( split.length == 1 ) {
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria criteriaPrice =
new Criteria("item_price").greaterThanEqual(split[0]);
filterQuery.addCriteria(criteriaPrice);
query.addFilterQuery(filterQuery);
} else if ( split.length == 2 ){
FilterQuery filterQuery = new SimpleFilterQuery();
Criteria criteriaPrice =
new Criteria("item_price").greaterThanEqual(split[0]);
criteriaPrice =
criteriaPrice.and("item_price").lessThanEqual(split[1]);
filterQuery.addCriteria(criteriaPrice);
query.addFilterQuery(filterQuery);
}
}
//分页
Integer pageNum = (Integer) map.get("pageNum");
Integer pageSize = (Integer) map.get("pageSize");
if ( pageNum == null ) {
pageNum = 1;
}
if ( pageSize == null ) {
pageSize = 10;
}
query.setOffset((pageNum-1)*pageSize);
query.setRows(pageSize);
//排序
String sortField = (String) map.get("sortField");
String sortStr = (String) map.get("sort");
if (StringUtils.isNotEmpty(sortField)&&StringUtils.isNotEmpty(sortStr)) {
if (sortStr.equals("ASC")) {
Sort sort = new Sort(Sort.Direction.ASC,"item_"+sortField);
query.addSort(sort);
}
if (sortStr.equals("DESC")) {
Sort sort = new Sort(Sort.Direction.DESC,"item_"+sortField);
query.addSort(sort);
}
}
HighlightPage highlightPage =
solrTemplate.queryForHighlightPage(query, TbItem.class);
//遍历高亮结果
List> highlighted = highlightPage.getHighlighted();
if (highlighted != null && highlighted.size() > 0) {
for (HighlightEntry tbItemHighlightEntry : highlighted) {
TbItem tbItem = tbItemHighlightEntry.getEntity();
List highlights =
tbItemHighlightEntry.getHighlights();
if (highlights != null && highlights.size() > 0) {
for (HighlightEntry.Highlight highlight : highlights) {
//获取分片结果集
List snipplets = highlight.getSnipplets();
String title = snipplets.get(0);
tbItem.setTitle(title);
}
}
}
}
List tbItems = highlightPage.getContent();
//总记录数
long totalElements = highlightPage.getTotalElements();
//总页数
int totalPages = highlightPage.getTotalPages();
result.put("totals", totalElements);
result.put("totalPages", totalPages);
result.put("rows", tbItems);
return result;
}
至此,关于 Solr 在Java中的使用就介绍完啦~