連載
» 2009年03月27日 00時00分 公開

全文検索エンジン「Lucene.Net」を使う連載:VBで実践! 外部コンポーネント活用術(3/3 ページ)

[岸本真二郎,デジタルアドバンテージ]
前のページへ 1|2|3       

検索アプリケーションを作成

 続いては、次のような画面の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についてのドキュメントや書籍などが参考になるでしょう。

「連載:VBで実践! 外部コンポーネント活用術」のインデックス

連載:VBで実践! 外部コンポーネント活用術

前のページへ 1|2|3       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。