2008年1月10日木曜日

MeCabによるフルテキスト検索対応

いろいろ悩みつつもなんとかテストできた。結構トラブルがあったので忘れないようにメモ。

1:SQLCLRでのアセンブリ権限
今回のように外部プログラムを実行する場合、権限は「無制限」でないと実行できない。そのためにはデータベースのプロパティの設定、またはログイン周りでの権限設定が必要。今回はデータベースのプロパティ設定にて対応した。

-- TRUSTWORTHYプロパティの設定
ALTERDATABASE KEIWASET TRUSTWORTHY ON

そして今回は実際にログインするアカウントには管理者権限を与えていないので、SQLCLRビルド時は権限を「安全」にして配置を行う。

2:データベースの所有者
今までは気にしていなかったけど、「SqlServerのセキュリティにはWindowsグループで登録されていて、そこに属するユーザーでデータベースを構築した」際には、データベースの所有者欄に何も表示されていない状態になる。このままだとアセンブリの権限設定を行うことができないので、明示的に所有者を再設定する必要がある。
権限設定に必要な条件として、「SqlServerのセキュリティに登録されているログイン(≠グループ)」であり、その「ログインがデータベースの所有者となっている」必要があるみたい。
SqlServerのセキュリティに明示的にアカウントを追加し、その後ManagementStudioなどからデータベースのプロパティを開き、ファイルのページにある所有者を明示的に設定する。

SQLCLRの中身としては、今までの開発とほぼ同じなので楽々。気にしないといけないのは、デフォルトで参照設定できるアセンブリは限られているってところくらい。
そこを除けばT-SQLでゴリゴリ書くよりも大分楽だし、できることがたくさん増えるのですばらしいですわ。
T-SQLで外部プログラムを実行するためには、悪名高いXP_CMDSHELLを使う必要が高い(もう一つはOLEを利用するのでかなり限定されてしまう)し、しかも標準入出力を使うことができないからどうしても面倒が多いんだよね。ということで実際のSQLCLRで作成したMeCabを起動するためのロジックを。

Imports System  
Imports System.Data  
Imports System.Data.SqlClient  
Imports System.Data.SqlTypes  
Imports Microsoft.SqlServer.Server  
Imports System.Runtime.InteropServices  

Partial Public Class UserDefinedFunctions   

  Private Const _mecab_InstallPathAsString ="D:\Tool\MeCab\Bin\" 
  Private Const _mecab_FilenameAsString ="MeCab.Exe" 
  Private Const _mecab_WakatiOptionAsString ="-O wakati"  

  <Microsoft.SqlServer.Server.SqlFunction()> _ 
  PublicSharedFunction UP_CLR_DevideStrings(ByVal targetStrings As SqlString) As SqlString 
    ' コードをここに追加してください 
    If targetStrings.ToString.Trim.Equals("")Then Return Nothing 

    Dim resultStringAsString 
    Using mecabProcessAsNew System.Diagnostics.Process 
      With mecabProcess 
        With .StartInfo 
          .RedirectStandardOutput =True 
          .RedirectStandardInput =True 
          .CreateNoWindow =True 
          .UseShellExecute =False 
          .WorkingDirectory = _mecab_InstallPath 
          .FileName = _mecab_InstallPath + _mecab_Filename 
          .Arguments = _mecab_WakatiOption 
        EndWith 
        .Start() 
        .StandardInput.WriteLine(targetStrings) 
        resultString = .StandardOutput.ReadLine 
      EndWith 
    End Using 
    ReturnNew SqlString(resultString) 
  EndFunction 
EndClass

現地環境のときにもきっと同じ事で悩みそうだから忘れないようにしないとね。

0 件のコメント:

コメントを投稿