全文検索エンジン「Lucene.Net」を使う:連載:VBで実践! 外部コンポーネント活用術(3/3 ページ)
サイト構築などで使用できる検索エンジンをVBで活用。日本語アナライザを用いたインデックス作成から検索アプリ作成まで。
検索アプリケーションを作成
続いては、次のような画面のWindowsフォーム・アプリケーションを作成し、テキストボックスに入力された文字列を、先ほど作成した.NET TIPSの記事タイトルが格納されているインデックスから検索する処理を実装してみます。
検索処理を行うには、まず検索対象とするフィールド(Fieldオブジェクト)と、使用するアナライザ(JapaneseAnalyzerオブジェクト)を指定して、QueryParserオブジェクトを作成します。そして、テキストボックスに入力された文字列をパラメータにしてParseメソッドを実行し、Queryオブジェクトを作成します。
次に、インデックスのあるフォルダを指定してIndexSearcherオブジェクトを作成します。そして、いま作成したQueryオブジェクトをパラメータにして、Searchメソッドを実行すると、検索処理が行われます。
検索結果はHitsオブジェクトとして返されます。これには検索にヒットしたDocumentオブジェクトのリストが含まれるので、これを順番に表示すれば検索結果を表示できます。ヒットしたDocumentオブジェクトのスコアは、Scoreプロパティで取得できます。
Lukeの使用例でも触れましたが、検索処理で重要な点は、インデックス作成時のアナライザと、検索処理を行う際に使用するアナライザは同一のものを使用することです。そうしないとトークンの分割方法が一致せず、期待する検索結果が得られなくなる場合があります。さらに日本語アナライザが参照する辞書も同じ内容のものを使用するようにしておきます。
Imports Lucene.Net.QueryParsers
Imports Lucene.Net.Search
Imports Lucene.Net.Documents
Imports Lucene.Net.Analysis
Imports Lucene.Net.Analysis.Ja
Public Class Form1
Private Sub button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles button1.Click
Dim str As String = Me.textBox1.Text
'日本語アナライザの準備
Dim analyzer As Analyzer = _
New JapaneseAnalyzer("analyzer-mecab.xml")
Dim queryPsr As New QueryParser("title", analyzer)
Dim query As Query = queryPsr.Parse(str)
Dim searcher As New IndexSearcher("c:\lucene-index")
Dim hits As Hits = searcher.Search(query)
Dim s As String = ""
Dim i As Integer
For i = 0 To hits.Length() - 1 Step i + 1
Dim doc As Document = hits.Doc(i)
Dim id As Integer = hits.Id(i)
Dim url As String = doc.Get("url")
Dim title As String = doc.Get("title")
Dim score As Double = hits.Score(i) ' スコア
s += String.Format("{0:0.000}:{1}({2}){3}",_
score, title, url, vbCrLf)
Next
Me.textBox2.Text = s
End Sub
End Class
Webサイトでの全文検索処理を実現する
上記のWindowsアプリケーションで行ったような検索処理をASP.NETによるWebサイトで行えば、Webサイトに全文検索機能を追加できます。ここでは、いまWindowsアプリケーションで実装した処理内容を、今度はASP.NETで実装してみます。
■検索ページ
検索ページには、検索文字列を入力するテキストボックスと、検索を開始するためのボタン、さらに検索にヒットした件数を表示するためのラベルと、検索結果を表示するためのDataListコントロールを配置しています。検索時の画面を次に示します。
このページの内容を次に示します。
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="vbWebApplication._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server" defaultbutton="Button1">
<div>
<!-- テキストボックス -->
検索語:<asp:TextBox ID="TextBox1" runat="server" />
<!-- ボタン -->
<asp:Button ID="Button1" runat="server" Text="検索"
onclick="Button1_Click" />
<hr />
<!-- ラベル -->
ヒット数:<asp:Label ID="Label1" runat="server" Text="0" />
<hr />
<!-- DataListコントロール -->
<asp:DataList id="MyDataList" runat="server"
RepeatColumns="1" Width="100%" >
<FooterTemplate>
<hr/>
</FooterTemplate>
<ItemTemplate>
<%# DataBinder.Eval(Container.DataItem, "Score") %>:
<a href='<%# DataBinder.Eval(Container.DataItem,"Url")%>' >
<%# DataBinder.Eval(Container.DataItem, "Title") %>
</a>
</ItemTemplate>
</asp:DataList>
</div>
</form>
</body>
</html>
[検索]ボタンがクリックされてポストバックされると、入力された検索文字列からQueryオブジェクトを作成して検索を行います。
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Dim searchWord As String = Me.TextBox1.Text
Dim analyzer As Analyzer = _
New JapaneseAnalyzer("C:\inetpub\analyzer-mecab.xml")
Dim queryPsr As New QueryParser("title", analyzer)
Dim query As Query = queryPsr.Parse(searchWord)
Dim searcher As New IndexSearcher("c:\inetpub\lucene-index")
Dim hits As Hits = searcher.Search(query)
Dim tbl As New DataTable("Result")
Dim row As DataRow
tbl.Columns.Add("Url", System.Type.GetType("System.String"))
tbl.Columns.Add("Title", System.Type.GetType("System.String"))
tbl.Columns.Add("Score", System.Type.GetType("System.String"))
Label1.Text = hits.Length().ToString() ' ヒット数
For i As Integer = 0 To hits.Length() - 1
Dim doc As Lucene.Net.Documents.Document = hits.Doc(i)
Dim url As String = doc.Get("url")
Dim title As String = doc.Get("title")
Dim score As Single = hits.Score(i)
row = tbl.NewRow()
row("Url") = url
row("Title") = title
row("Score") = String.Format("{0:0.000}", score)
tbl.Rows.Add(row)
Next
Me.MyDataList.DataSource = tbl
Me.MyDataList.DataBind()
End Sub
検索結果をDataTableオブジェクトに格納し、DataListコントロールにバインドする。各レコードの表示は、.aspxファイルに記述した<ItemTemplate>要素の内容に従って行われる。
なお、Webアプリケーションでは、IISを実行するアカウント(Windows Server 2003では、デフォルトで「Network Service」)がインデックスにアクセスする権限を持っている必要があります。
.NET環境では貴重な全文検索エンジン
Webサイトに全文検索サービスを実装する場合、現在ではGoogleが提供するカスタムサーチやSQL Serverの全文検索機能なども利用できますが、Lucene.NETを用いると、スタティックなHTMLファイルに加えて、データベースやほかの形式のデータからもインデックスを作成して検索処理を実現可能です。
また、ここでは紹介できませんでしたが、このほかにもDocumentオブジェクトに含まれるフィールドごとにアナライザを変更したり、検索時にどのフィールドを対象にするかを指定したりといった細かなコントロールも可能で、目的に応じた柔軟な検索処理が実現できます。
そもそも.NETベースの環境で利用できる全文検索エンジンはそれほど選択肢がありませんが、Lucene.NETは非常に優れた検索エンジンといえます。Lucene.NETの詳細についての日本語のドキュメントは残念ながら豊富ではありませんが、オリジナルであるLuceneについてのドキュメントや書籍などが参考になるでしょう。
Copyright© Digital Advantage Corp. All Rights Reserved.