本节我给大家测试一下Linux环境的Solr,通过增删改查的实例demo看看Solr环境是否已经OK。记得有哥们留言,问到只看见Solr和Cassandra的单独环境搭建,却不见它们的协同。我想说这两个没有什么必然的联系,在Cassandra的DSE版本,在Cassandra的内部继承了一套Solr的环境,只需要开启开关,就可以自动往Solr同步数据。但是这个嵌入的版本性能太差,无法使用。那么它们之间要怎么样联系呢?因为cassandra的二级索引查询速度不尽如人意,而且查询的语法有限,所以我们引入Solr,用Solr查询出主键,再去Cassandra根据主键查询出想要的速度,总结来说就是Solr中存储一些用于查询的字段,而Cassandra中存储所有要用到的数据,Solr负责查询,Cassandra集群负责数据。


这两天在使用Solr的时候碰到一个问题,由于我的Schema定义如下

大数据实战之环境搭建(七)_Github

当时我少定义了一个uniqueKey,结果报错,但是我加上后重启Tomcat,还是报这个错误,后来一直没解决掉。第二天,我发现居然自己好了,于是看了一下Tomcat的bin目录,没有shutdown.sh,只有startup.sh。我想着是不是因为没有shutdown的原因,我就采用kill进程的方式,关闭了一下tomcat,然后重启,发现就是因为没有关闭tomcat的原因。

[root@bogon ~]# ps -ef |grep tomcat
root      5079     1  3 23:02 ?        00:00:20 /usr/java/jdk1.7.0_21/bin/java -Djava.util.logging.config.file=/usr/apache-tomcat-7.0.40/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/apache-tomcat-7.0.40/endorsed -classpath /usr/apache-tomcat-7.0.40/bin/bootstrap.jar:/usr/apache-tomcat-7.0.40/bin/tomcat-juli.jar -Dcatalina.base=/usr/apache-tomcat-7.0.40 -Dcatalina.home=/usr/apache-tomcat-7.0.40 -Djava.io.tmpdir=/usr/apache-tomcat-7.0.40/temp org.apache.catalina.startup.Bootstrap start
root      6128  6093  0 23:12 pts/0    00:00:00 grep tomcat
[root@bogon ~]# kill -9 5079
[root@bogon ~]# cd /usr
[root@bogon usr]# cd apache-tomcat-7.0.40
[root@bogon apache-tomcat-7.0.40]# cd bin
[root@bogon bin]# sh startup.sh
Using CATALINA_BASE:   /usr/apache-tomcat-7.0.40
Using CATALINA_HOME:   /usr/apache-tomcat-7.0.40
Using CATALINA_TMPDIR: /usr/apache-tomcat-7.0.40/temp
Using JRE_HOME:        /usr/java/jdk1.7.0_21
Using CLASSPATH:       /usr/apache-tomcat-7.0.40/bin/bootstrap.jar:/usr/apache-tomcat-7.0.40/bin/tomcat-juli.jar

OK,既然没有问题,我们进入正题,修改Sol实例目录下的SolrConfig.xml文件中的内容

<cores adminPath="/admin/cores" defaultCoreName="MyTest.UserInfo" host="${host:}" hostPort="${jetty.port:8080}" hostContext="${hostContext:solr}" zkClientTimeout="${zkClientTimeout:15000}">
<core name="MyTest.UserInfo" instanceDir="Test" />
</cores>

Core Name设置为MyTest.UserInfo。

OK,重新启动Solr,我们打开浏览器,如下

大数据实战之环境搭建(七)_SolrNet_02

我们实例名称已经成为刚才设置的名称(MyTest.UserInfo)。


接下来我们要看的是我们的程序

大数据实战之环境搭建(七)_SolrNet_03

Entity下面是我们定义的Solr实体,如下

namespace SolrCURDDemo
{
using SolrNet;
using SolrNet.Attributes;
public class UserInfoEntity
{
public UserInfoEntity() { }
[SolrUniqueKey("UserNO")]
public string UserNO { get; set; }
[SolrField("Name")]
public string Name { get; set; }
[SolrField("Age")]
public int? Age { get; set; }
[SolrField("IsMarried")]
public bool? IsMarried { get; set; }
}
}

和我们刚才定义的Solr Schema一致。然后Reference下面是我们要引用的dll,SolrNet.dll和Microsoft.Practises.ServiceLocation.dl。我下载的SolrNet是0.4.0.2002,大家在网上自己去下。

接下来是我们的SolrConfig配置文件,这个是我自定义的一个xml文件

<?xml version="1.0" encoding="utf-8" ?>
<SolrConfigCollection>
<SolrConfigs baseAddress="Http://192.168.192.128:8080/MyTest.">
<Schema name="UserInfo" entityName="SolrCURDDemo.UserInfoEntity"></Schema>
</SolrConfigs>
<!--<SolrConfigs baseAddress="Http://192.168.192.128:8080/MyOtherTest.">
<Schema name="UserInfo"></Schema>
</SolrConfigs>-->
</SolrConfigCollection>

什么意思呢?在这里我的意思是 一个地址可以有多个Schema,或者多个地址,假如我有这样的一个需求,一个Solr服务负责学生的基信息,一个Solr服务负责学生的成绩信息,那么我们就配置两个SolrConfigs。

接下来是我们Utility,主要是SolrHelper和SolrCollection类

namespace SolrCURDDemo
{
using SolrNet;
using Microsoft.Practices.ServiceLocation;
using System.Reflection;
using SolrNet.Commands.Parameters;
using System.Configuration;
public class SolrHelper
{
private static bool isRegister;
private static SolrHelper solrHelper = new SolrHelper();
private SolrHelper()
{ }
private static int MaxQueryCount
{
get
{
return int.Parse(ConfigurationManager.AppSettings["MaxQueryCount"].ToString());
}
}
public static SolrHelper GetInstance()
{
if (!isRegister)
{
RegisterSolrInstance();
isRegister = true;
}
return solrHelper;
}
private static void RegisterSolrInstance()
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"\SolrConfig\SolrConfig.xml";
SolrCollection solrCollection = Deserialize<SolrCollection>(path);
Type startUpType = typeof(Startup);
foreach (SolrConfigs solrConfig in solrCollection.SolrConfigs)
{
foreach (SchemaInfo schema in solrConfig.Schemas)
{
MethodInfo method = startUpType.GetMethod("Init", new Type[] { typeof(string) })
.MakeGenericMethod(Type.GetType(schema.EntityType));
method.Invoke(null, new object[] { solrConfig.BaseAddress + schema.ServiceName });
}
}
}
private static T Deserialize<T>(string path) where T : class,new()
{
XmlReader xmlReader = XmlReader.Create(path);
XmlSerializer xmlSer = new XmlSerializer(typeof(SolrCollection));
object deSerializeObj = xmlSer.Deserialize(xmlReader);
xmlReader.Close();
return deSerializeObj as T;
}
private ISolrOperations<T> GetSolrOperation<T>()
{
return ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
}
#region solr operations
#region query
public List<T> QueryByFilter<T>(string filter)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
SolrQueryResults<T> result = solrOperation.Query(filter);
return result.ToList();
}
catch (Exception ex)
{
throw ex;
}
}
public List<T> QueryByFilter<T>(ISolrQuery solrQuery)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
SolrQueryResults<T> result = solrOperation.Query(solrQuery);
return result.ToList();
}
catch (Exception ex)
{
throw ex;
}
}
public List<T> QueryByFilter<T>(string filter, Dictionary<string, string> sortDictionary)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
List<SortOrder> sortOrderList = new List<SortOrder>();
foreach (KeyValuePair<string, string> sortPair in sortDictionary)
{
SortOrder sortOrder = new SortOrder(sortPair.Key, (Order)Enum.Parse(typeof(Order), sortPair.Value));
sortOrderList.Add(sortOrder);
}
SolrQueryResults<T> result = solrOperation.Query(filter, sortOrderList);
return result.ToList();
}
catch (Exception ex)
{
throw ex;
}
}
public List<T> QueryByFilter<T>(ISolrQuery solrQuery, Dictionary<string, string> sortDictionary)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
List<SortOrder> sortOrderList = new List<SortOrder>();
foreach (KeyValuePair<string, string> sortPair in sortDictionary)
{
SortOrder sortOrder = new SortOrder(sortPair.Key, (Order)Enum.Parse(typeof(Order), sortPair.Value));
sortOrderList.Add(sortOrder);
}
SolrQueryResults<T> result = solrOperation.Query(solrQuery, sortOrderList);
return result.ToList();
}
catch (Exception ex)
{
throw ex;
}
}
public List<T> QueryByFilter<T>(string filter, int pageIndex, int pageSize)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
QueryOptions queryOptions = new QueryOptions();
queryOptions.Start = pageIndex;
queryOptions.Rows = pageSize;
if (pageSize > MaxQueryCount)
{
queryOptions.Rows = MaxQueryCount;
}
SolrQueryResults<T> result = solrOperation.Query(filter, queryOptions);
return result.ToList();
}
catch (Exception ex)
{
throw ex;
}
}
public List<T> QueryByFilter<T>(ISolrQuery solrQuery, int pageIndex, int pageSize)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
QueryOptions queryOptions = new QueryOptions();
queryOptions.Start = pageIndex;
queryOptions.Rows = pageSize;
if (pageSize > MaxQueryCount)
{
queryOptions.Rows = MaxQueryCount;
}
SolrQueryResults<T> result = solrOperation.Query(solrQuery, queryOptions);
return result.ToList();
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
#region add
public int AddEntity<T>(T entity)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.Add(entity);
solrOperation.Commit();
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
public int AddEntityList<T>(List<T> entityList)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.AddRange(entityList);
solrOperation.Commit();
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
#region delete
public int DeleteByEntity<T>(T entity)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.Delete(entity);
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
public int DeleteByKey<T>(string key)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.Delete(key);
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
public int DeleteByEntityList<T>(List<T> entityList)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.Delete(entityList);
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
public int DeleteByKeyList<T>(List<string> keyList)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.Delete(keyList);
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
public int DeleteByFilter<T>(ISolrQuery query)
{
try
{
ISolrOperations<T> solrOperation = GetSolrOperation<T>();
solrOperation.Delete(query);
return 1;
}
catch (Exception ex)
{
throw ex;
}
}
#endregion
#endregion
}
}

这里面主要是Solr的增删改查方法,需要说的下面的这个方法

private static void RegisterSolrInstance()
{
string path = AppDomain.CurrentDomain.BaseDirectory + @"\SolrConfig\SolrConfig.xml";
SolrCollection solrCollection = Deserialize<SolrCollection>(path);
Type startUpType = typeof(Startup);
foreach (SolrConfigs solrConfig in solrCollection.SolrConfigs)
{
foreach (SchemaInfo schema in solrConfig.Schemas)
{
MethodInfo method = startUpType.GetMethod("Init", new Type[] { typeof(string) })
.MakeGenericMethod(Type.GetType(schema.EntityType));
method.Invoke(null, new object[] { solrConfig.BaseAddress + schema.ServiceName });
}
}
}

就是我们第一次使用SolrHelper的时候,将配置文件中所有的Solr实例都进行注册,用的时候我们只需要通过下面的代码获取即可

private ISolrOperations<T> GetSolrOperation<T>()
{
return ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
}

接下来看我们的SolrCollection类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
namespace SolrCURDDemo
{
[XmlRoot("SolrConfigCollection")]
public class SolrCollection
{
[XmlElement("SolrConfigs")]
public SolrConfigs[] SolrConfigs;
}
public class SolrConfigs
{
[XmlElement("Schema")]
public SchemaInfo[] Schemas;
[XmlAttribute("baseAddress")]
public string BaseAddress;
}
public class SchemaInfo
{
[XmlAttribute("name")]
public string ServiceName;
[XmlAttribute("entityName")]
public string EntityType;
}
}

对应于我们的SolrConfig.xml文件,用于反序列化,结合SolrHelper中的Desrialize方法就能明白了。

OK,我们的窗体如下

大数据实战之环境搭建(七)_Github_04

OK,我们看一下保存代码很简单,如下

UserInfoEntity userInfoEntity = new UserInfoEntity();
           userInfoEntity.UserNo = userNo;
           userInfoEntity.Name = name;
           userInfoEntity.Age = age;
           userInfoEntity.IsMarried = isMarried;
           int suc = SolrHelper.GetInstance().AddEntity<UserInfoEntity>(userInfoEntity);

保存成功后,我们先在Solr中查询,结果如下

大数据实战之环境搭建(七)_SolrNet_05

接着我们在Demo中查询,代码如下

string filter = this.txtFilter.Text.Trim();
            if (filter == string.Empty)
            {
                CommonMessage.ShowMessage(Resources.Msg_Input_Filter);
                return;
            }
            try
            {
                List<UserInfoEntity> userInfoList = SolrHelper.GetInstance().QueryByFilter<UserInfoEntity>(filter);
                this.dgvSearchResult.DataSource = userInfoList;
                this.BuildRowNumber();
            }
            catch (Exception ex)
            {
                CommonMessage.ShowMessage(ex.Message);
            }

可以查询出结果

大数据实战之环境搭建(七)_Github_06

在得到这样的结果我不得不说,我上面的SolrConfig配置文件的内容应该是这样的

<?xml version="1.0" encoding="utf-8" ?>
<SolrConfigCollection>
  <SolrConfigs baseAddress="Http://192.168.192.128:8080/solr/MyTest.">
      <Schema name="UserInfo" entityName="SolrCURDDemo.UserInfoEntity"></Schema>
  </SolrConfigs>
  <!--<SolrConfigs baseAddress="Http://192.168.192.128:8080/solr/MyOtherTest.">
      <Schema name="UserInfo"></Schema>
  </SolrConfigs>-->
</SolrConfigCollection>

但是不知道怎么回事,我想改上面的地址,因为我少了/solr。但是51cto这个编辑器在chrome和IE9下没办法修改,甚至是我想整个删除都不行,郁闷了,再给大家贴一次。

我们再看看删除的代码

string userNo = txtUserNo.Text.Trim();
          if (userNo == string.Empty)
          {
              CommonMessage.ShowMessage(Resources.Msg_InputUserNo);
              return;
          }
          int suc = SolrHelper.GetInstance().DeleteByKey<UserInfoEntity>(userNo);

OK,这个删除是根据主键删除,还有根据实体删除,查询条件删除。看看SolrHelper类中的方法你就清楚了。在这里给大家推荐几个网站

http://en.wikipedia.org/wiki/Apache_Solr

http://wiki.apache.org/solr/

大家去学吧!

最后我想说的是大家下载solrNet的时候不要去官网下载,不知道怎么回事,官网的SolrNet-0.4.0.xx版本有问题,提交保存数据之后会报400错误,但是数据能保存进去,需要重启tomcat才能看到。所以建议大家去GitHub下载。GitHub链接地址:https://github.com/mausch/SolrNet

官网地址:http://code.google.com/p/solrnet/