2014年10月27日星期一

Solr_999_注意事項


  • 當資料庫欄位型態為 TINYINT(1)  時可能發生的問題
    由於MySQL資料庫對於此型態欄位優先定位為為儲存 boolean值使用,所以Field 的 FieldType 對於此欄位僅能設定為boolean type 或 string type,但是在某些情況之下為了節省資料庫儲存空間,也會使用此欄位儲存超過0及1的值,但是Field type 卻無法使用 int type 進行解析,如果要解決此問題必需在db-data-config.xml裡面加入 
    tinyInt1isBit="false" 
    強制關制solr將TINYINT(1)  解析為boolean值,修改後該對應的field type 就可以使用 int type
    <dataConfig>
        <dataSource type="JdbcDataSource" 
                    driver="com.mysql.jdbc.Driver" 
                    url="jdbc:mysql://localhost:3306/fusion" 
                    user="root" password="root"
                    tinyInt1isBit="false" />
        <document>
            <entity name="table" query="select * from xxxtable"
                    deltaQuery="select Updated from xxxtablewhere Updated > '${dataimporter.last_index_time}'">
                <field column="sid" name="sid"/>
                <field column="TinyintType" name="tinyintType"/> <!-- 假設此欄位是存放TINYINT(1) -->                 
            </entity>       
        </document>
    </dataConfig>


  • UTC世界協調時間
    由於Solr所建立的索引全都是採用UTC世界協調時間為主,所以當使用程式進行索引建立時,無需刻意轉換UTC的資料格式,但是當要使用日期格式建立查詢語句,必需使用UTC格式進行查詢
    import org.joda.time.DateTime;
    import org.joda.time.DateTimeZone;
     
    ....   
    public void someMethod(){ 
     DateTime now  = new DateTime(new Date());
     DateTime zulu = now.toDateTime(DateTimeZone.UTC);
     System.out.println(zulu)
    }
    假設台灣時間為 2014-10-06 08:00:00
    結果輸出UTC時間及格式為: 2014-10-06T00:00:00.000Z
    另外由於建立的索引都是以UTC時間為主,所以在Solr主控台中所看到的時間都會比台灣時間慢8個小時,當然在主控台下查詢語句時,記得要減8個小時。



Solr_900_其它

指定索引儲存位置

  1. 執行啟動指令時加入-Dsolr.data.dir
     java -Dsolr.data.dir=指定目錄位置 -DSTOP.PORT=8079 -DSTOP.KEY=1234 -jar start.jar

  2. 修改核心的solrconfig.xml檔案
    找到 <dataDir> 並將內容修改為
      <!-- Data Directory
           Used to specify an alternate directory to hold all index data
           other than the default ./data under the Solr home.  If
           replication is in use, this should match the replication
           configuration.
        -->
      <dataDir>${solr.data.dir:}/_acs</dataDir>

自定義核心變數

  • core.properties file
    #core.properties
    name=collection2
    my.custom.prop=edismax
    定義好的變數使用方式如下
    <requestHandler name="/select">
      <lst name="defaults">
        <str name="defType">${my.custom.prop}</str>
      </lst>
    </requestHandler>

Solr_10_JNDI連接

目前Solr 4.10 所使用的啟動Server 版本為 Jetty 8.1.10.v20130312,如果啟動Server不同JNDI設定方式也會不一樣。
  • 修改start.jar
    1. 到啟動 jetty 的資料夾,使用解壓縮軟體打開 start.jar 檔

    2. 將 org/eclipse/jetty/start/start.config 檔案,解壓到桌面

    3. 用文字編輯器打開start.config檔找到


      改成
    4. 請在default後面加入plus,修改完畢後,將start.config 檔案壓回 start.jar 檔內
  • 下載JETTY 8.0 資源
    1. 到eclipse 官網下載 jetty 8.0 所有jar檔 (solr 4.10 使用的jetty8 版本為 8.1.10.v20130312 )

    2. 解壓縮後到target/site/plugins/ 資料夾將以下的jar拉出來到 solrhome/lib 裡面
      1. org.eclipse.jetty.jndi_8.1.10.v20130312
      2. org.eclipse.jetty.plus_8.1.10.v20130312
    3. 並且修改jar檔的命名,格式跟lib資料夾內其它jar一樣即可,如果命名錯誤,start.config會讀不到。

  • 下載 mysql-connector-java-5.1.27.jar
    • 請放到solrhome/lib/ext 資料夾內

  • 編輯 solrhome/contexts/solr-jetty-context.xml 檔案
    1. 開啟檔案後請在最後面加入JNDI的設定
      <?xml version="1.0"?>
      <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
      <Configure class="org.eclipse.jetty.webapp.WebAppContext">
        <Set name="contextPath"><SystemProperty name="hostContext" default="/solr"/></Set>
        <Set name="war"><SystemProperty name="jetty.home"/>/webapps/solr.war</Set>
        <Set name="defaultsDescriptor"><SystemProperty name="jetty.home"/>/etc/webdefault.xml</Set>
        <Set name="tempDirectory"><Property name="jetty.home" default="."/>/solr-webapp</Set>
        <!-- 下方新增 Jndi resource -->
        <New id="fusion_db" class="org.eclipse.jetty.plus.jndi.Resource">
            <Arg>java:comp/env/jdbc/fusion</Arg>
            <Arg>
              <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
               <Set name="Url">jdbc:mysql://localhost:3306/fusion</Set>
               <Set name="User">root</Set>
               <Set name="Password">root</Set>
               <Set name="tinyInt1isBit">false</Set>
              </New>
            </Arg>
        </New>     
      </Configure>

  • 修改 solr core dbconfig設定
    1. 請到要修改成使用jndi讀取資料庫連結的核心conf資料內開啟db-xxx-config.xml檔案進行編輯

    2. 原本的dataSource大致上應該是長這樣
          <dataSource type="JdbcDataSource" 
                      driver="com.mysql.jdbc.Driver" 
                      url="jdbc:mysql://localhost:3306/fusion" 
                      user="root" 
                      password="root"
                      tinyInt1isBit="false"/>
      修改成使用jndiName讀取
      <dataSource type="JdbcDataSource" jndiName="java:comp/env/jdbc/fusion" />

  • 以上修改完成後,請到主控台測試是否正常連結


  • 請注意 在solr-jetty-context.xml 及 db-xxx-config.xml 此兩個檔案所存放的JNDI名稱必需一模一樣 否則會出現以下錯誤
    Caused by: javax.naming.NameNotFoundException; remaining name 'env/jdbc/fusion' at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:505) at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:536) at org.eclipse.jetty.jndi.NamingContext.lookup(NamingContext.java:551) at org.eclipse.jetty.jndi.java.javaRootURLContext.lookup(javaRootURLContext.java:117) at javax.naming.InitialContext.lookup(Unknown Source) at org.apache.solr.handler.dataimport.JdbcDataSource$1.getFromJndi(JdbcDataSource.java:211) at org.apache.solr.handler.dataimport.JdbcDataSource$1.call(JdbcDataSource.java:143) at org.apache.solr.handler.dataimport.JdbcDataSource$1.call(JdbcDataSource.java:133) at org.apache.solr.handler.dataimport.JdbcDataSource.getConnection(JdbcDataSource.java:402) at org.apache.solr.handler.dataimport.JdbcDataSource.access$200(JdbcDataSource.java:44) at org.apache.solr.handler.dataimport.JdbcDataSource$ResultSetIterator.<init>(JdbcDataSource.java:270) ... 12 more
    

  • 如果設定檔設定錯誤或是打錯,基本上應該會出現Xml解析錯誤的錯誤訊息
參考資料

參考資料都無法設定成功,所以看看就好

Solr_09_建立solr系統驗證

1.到 C:\solr-4.10.0\example\etc 資料夾
編輯jetty.xml
加入以下內容
   <Call name="addBean">
      <Arg>
        <New class="org.eclipse.jetty.security.HashLoginService">
          <Set name="name">Solr Realm</Set>
          <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
          <Set name="refreshInterval">0</Set>
        </New>
      </Arg>
    </Call>
2.編輯webdefault.xml
加入以下內容
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Solr authenticated application</web-resource-name>
      <url-pattern>/</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin-role</role-name>
    </auth-constraint>
  </security-constraint>
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Solr Realm</realm-name>
  </login-config>
新增realm.properties檔案
內容格式如下
admin: password, admin-role
solrjAPI使用時進行驗證
新增PreemptiveAuthInterceptor.java 內容如下
/*
 * To change this license header, choose License Headers in Project Properties. To change this
 * template file, choose Tools | Templates and open the template in the editor.
 */
package com.cy.solrjsearch;
import java.io.IOException;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.ContextAwareAuthScheme;
import org.apache.http.auth.Credentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 
 * @author shaun
 */
public class PreemptiveAuthInterceptor implements HttpRequestInterceptor {
  private static final Logger logger = LoggerFactory.getLogger(PreemptiveAuthInterceptor.class);
  protected ContextAwareAuthScheme authScheme = new BasicScheme();
  @Override
  public void process(final HttpRequest request, final HttpContext context) throws HttpException,
      IOException {
    AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
    // If no auth scheme avaialble yet, try to initialize it
    // preemptively
    if (authState.getAuthScheme() == null) {
      CredentialsProvider credsProvider =
          (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);
      HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
      Credentials creds =
          credsProvider
              .getCredentials(new AuthScope(targetHost.getHostName(), targetHost.getPort()));
      if (creds == null) throw new HttpException("No credentials for preemptive authentication");
      authState.setAuthScheme(new BasicScheme());
      authState.setCredentials(creds);
    }
  }
  public ContextAwareAuthScheme getAuthScheme() {
    return authScheme;
  }
  public void setAuthScheme(final ContextAwareAuthScheme authScheme) {
    this.authScheme = authScheme;
  }
}

在引用SolrServer時需修改如下
    PoolingClientConnectionManager cxMgr =
        new PoolingClientConnectionManager(SchemeRegistryFactory.createDefault());
    cxMgr.setMaxTotal(100);
    cxMgr.setDefaultMaxPerRoute(20);
    DefaultHttpClient httpclient = new DefaultHttpClient(cxMgr);
    httpclient.addRequestInterceptor(new PreemptiveAuthInterceptor(), 0);
    httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY,
        new UsernamePasswordCredentials("admin", "admin"));
    solr = new HttpSolrServer(URL, httpclient);
    solr.setRequestWriter(new BinaryRequestWriter());
    solr.setAllowCompression(true);
如果單純只有query的話,就不用那麼麻煩
    HttpSolrServer solr = new HttpSolrServer(URL);
    HttpClientUtil.setBasicAuth((DefaultHttpClient) solr.getHttpClient(), "admin", "admin");

Solr_08_05_IK分詞器設置

  • 分詞器 jar 一樣放在core的lib資料夾
  • 分詞器用來擴展停止詞彙索引的檔案,放置位置。在本例中solrApp專案對應的位置在 C:\Users\shaun\Documents\solrApp\src\main\webapp\WEB-INF\classes


    classes資料夾請自己建立

Solr_08_04_設定、啟動、佈署

  • 請先運行Glassfish,然後進入 Admin Console 並新增兩個伺服器系統特性
    1. solr.data.dir      -> 預設索引存放位置
    2. solr.solr.home  -> 實際core的位置(該位置有solr.xml檔案)
  • 停止Glassfish執行,重新用NetBeans啟動,讓solrApp專案可以佈署到Glassfish上
    也可以直接在admin console 進行佈署,或是將solrApp-1.0-SNAPSHOT.war 丟到 Glassfish的autodeploy資料夾。

  • 在啟動過程中,如果有任何重大錯誤請想辦法除錯,否則後續系統運作會不正常,如果佈署成功後會直接跳出Solr Admin的畫面(如果不要直接跳出來,請修改web.xml設定)

Solr_08_03_solrApp專案設定調整

  • 編輯solrApp專案pom.xml。(只有修改dependencies部份)
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        .......
        <dependencies>
            <!-- 
               Solr自帶的Guava 14.0.1在GlassFish啟動時,會導致CDI deployment failure:WELD-001408錯誤,
               所以需要刪除自帶的Guava ,並導入最新的Guava
            -->
            <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>17.0</version>
            </dependency>
            <!-- 
               加這個相依是因為glassfish啟動時,會出現下面的警告
               Unable to load class org.apache.hadoop.hdfs.web.resources.UserProvider
               reason: java.lang.NoClassDefFoundError: com/sun/jersey/spi/inject/InjectableProvider
            -->
            <dependency>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-bundle</artifactId>
                <version>1.9.1</version>
            </dependency>
        </dependencies>
        .......
    </project>
    

    就算沒有加 jersey-bundle的dependency也不會影響solrApp運作

  • 刪除solr本身自帶的guava.jar

  • 到 C:\solr\example\ 資料夾底下,將solr資料夾整個複製到c槽並且重新命名為solrhome,並且再新增一個solrdata資料夾。


    solr資料夾指的就是啟動時,引用core的那個資料夾,而且非強制重命名。

  • 如果02_建立DB CORE並查詢這個步驟有完成,可以順便把db core放進去solrhome資料夾,但是要另外將 C:\solr\ 資料夾 的contribdist 資料夾一同複製放到solrhome裡面去

    加入contrib、dist這兩個資料夾是因為db core的solrconfig.xml有引用

  • 如果放入db core,需要重新編輯 C:\solrhome\db\conf\solrconfig.xml ,將lib的引用路徑進行修正。
      <lib dir="../dist/" regex="solr-dataimporthandler-.*\.jar" />
      <lib dir="../contrib/extraction/lib" regex=".*\.jar" />
      <lib dir="../dist/" regex="solr-cell-\d.*\.jar" />
      <lib dir="../contrib/clustering/lib/" regex=".*\.jar" />
      <lib dir="../dist/" regex="solr-clustering-\d.*\.jar" />
      <lib dir="../contrib/langid/lib/" regex=".*\.jar" />
      <lib dir="../dist/" regex="solr-langid-\d.*\.jar" />
      <lib dir="../contrib/velocity/lib" regex=".*\.jar" />
      <lib dir="../dist/" regex="solr-velocity-\d.*\.jar" />