ヘッダーをスキップ
Oracle® Textアプリケーション開発者ガイド
11gリリース2 (11.2)
B61358-04
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

A CONTEXT問合せアプリケーション

この付録では、独自のコードを記述するか、またはOracle Textウィザードを使用して、CONTEXT索引タイプを使用した簡単なWeb検索アプリケーションを作成する方法を説明します。次の項目について説明します。

A.1 Web問合せアプリケーションの概要

Oracle Textの一般的な使用目的は、Webサイト上のHTMLファイルを索引付けし、ユーザーに検索機能を提供することです。この付録のサンプル・アプリケーションでは、データベースに格納されているHTMLファイルのセットを索引付けし、Oracle Databaseに接続しているWebサーバーを使用して検索サービスを提供します。

この付録では、Web問合せアプリケーションの次の2つのバージョンについて説明します。

  • PL/SQL Server Pages(PSP)を使用するバージョン

  • Java Server Pages(JSP)を使用するバージョン

これらのアプリケーションのバージョンは両方とも、必要なコードを自動的に作成する問合せアプリケーション・ウィザードを使用して作成できます。

PSP、JSP両方のアプリケーション・コードおよびテキスト問合せアプリケーション・ウィザードは、次のOracle Technology NetworkのWebサイトで表示およびダウンロードできます。

http://www.oracle.com/technology/products/text

テキスト問合せアプリケーション・ウィザードのWebページには、このウィザードの使用方法の詳細な説明もあります。

図A-1に、テキスト問合せアプリケーションのJSPバージョンはどのようなものかを示します。このアプリケーションは、Oracle Textアプリケーション・ウィザードを使用して作成されています。

図A-1 テキスト問合せアプリケーション

図A-1の説明は次にあります。
「図A-1 テキスト問合せアプリケーション」の説明

図A-2に、テキスト問合せの結果を示します。

図A-2 結果を表示したテキスト問合せアプリケーション

図A-2の説明は次にあります。
「図A-2 結果を表示したテキスト問合せアプリケーション」の説明

このアプリケーションでは、検索用語を含むドキュメントへのリンクを戻します。各ドキュメントには、次の4つのリンクがあります。

A.2 PSP Webアプリケーション

このアプリケーションは、PL/SQL Server Pagesに基づいています。図A-3「PSP Webアプリケーション」は、ブラウザが、Webサーバーを経由してOracle DatabaseのPSPストアド・プロシージャをコールする方法を示しています。

図A-3 PSP Webアプリケーション

図A-3の説明は次にあります。
「図A-3 PSP Webアプリケーション」の説明

A.2.1 Webアプリケーションの前提条件

このアプリケーションには、次の要件があります。

  • Oracle Database(リリース8.1.6以上)が起動され、実行中であること。

  • Oracle PL/SQL Gatewayが実行中であること。

  • ApacheなどのWebサーバーが起動され、実行中であり、Oracle Databaseに要求を送信するように適切に構成されていること。

A.2.2 Webアプリケーションの作成

この項では、PSP Webアプリケーションの作成方法を説明します。

手順1   テキスト表の作成

HTMLファイルを格納するテキスト表を作成する必要があります。この例では、次のようにsearch_tableという表を作成します。

create table search_table (tk numeric primary key, title varchar2(2000), 
  text clob);
手順2   HTMLドキュメントのテキスト表へのロード(SQL*Loaderを使用)

テキスト表は、HTMLファイルを使用してロードする必要があります。この例では、制御ファイルloader.ctlを使用して、loader.datで指定したファイルをロードします。SQL*Loader文は次のとおりです。

% sqlldr userid=scott/tiger control=loader.ctl 
手順3   CONTEXT索引の作成

テキスト問合せウィザードを使用している場合: このウィザードにより、索引を作成するスクリプトが作成されます。(ダウンロードしたWebページの、ウィザードについての説明を参照してください。)そのスクリプトを実行します。

ウィザードを使用していない場合: HTMLファイルを索引付けするには、次のようにCONTEXT索引をテキスト列に作成します。HTMLの索引付けであるため、この例では、フィルタ処理が不要なNULL_FILTERプリファレンス型とHTML_SECTION_GROUP型を使用します。

create index idx_search_table on search_table(text)
  indextype is ctxsys.context parameters
  ('filter ctxsys.null_filter section group CTXSYS.HTML_SECTION_GROUP');
手順4   Oracle Databaseでのsearch_htmlservicesパッケージのコンパイル

アプリケーションには、選択したドキュメントが表示される必要があります。このために、Oracle Databaseではsearch_tableCLOBからドキュメントを読み取り、その結果を出力して表示する必要があります。これは、search_htmlservicesパッケージ内のプロシージャをコールして実行します。ファイルsearch_htmlservices.sqlをコンパイルする必要があります。この操作は、SQL*Plusプロンプトで実行できます。

SQL> @search_htmlservices.sql

Package created.
手順5   search_html PSPページのコンパイル(loadpspを使用)

検索ページを呼び出すには、ブラウザからsearch_html.pspをコールします。search_htmlは、Oracle Databaseのloadpspコマンドライン・プログラムを使用して、次のようにコンパイルします。

% loadpsp -replace -user scott/tiger search_html.psp
"search_html.psp": procedure "search_html" created.

関連項目

PSPの使用方法の詳細は、『Oracle Databaseアドバンスト・アプリケーション開発者ガイド』を参照してください。

手順6   Webサーバーの構成

クライアントのPSP要求をURLとして受け入れるように、Webサーバーを構成する必要があります。Webサーバーは、クライアントの要求をOracle Databaseに転送し、サーバー出力をブラウザに戻します。図A-3を参照してください。

Oracle WebDB Webリスナー、またはApache Webサーバーが組み込まれているOracle Application Serverを使用できます。詳細は、使用しているWebサーバーのマニュアルを参照してください。

手順7   ブラウザからの問合せの入力

URLを使用して、ブラウザから問合せアプリケーションにアクセスできます。URLをWebサーバーで構成します。URLの例は、次のようになります。

http://server.example.com:7777/mypath/search_html

図A-1および図A-2で示すように、アプリケーションでは、ブラウザに問合せのエントリ・ボックスを表示し、問合せ結果をHTMLリンクのリストとして戻します。

A.2.3 PSPのサンプル・コード

この項では、Webアプリケーションのサンプルの作成に使用するコードを示します。次のファイルを記載しています。

A.2.3.1 loader.ctl

この例では、loader.ctlファイルのサンプルを示します。sqlldrでは、このファイルを使用してデータファイルloader.datがロードされます。

LOAD DATA 
        INFILE 'loader.dat'
        INTO TABLE search_table 
        REPLACE 
        FIELDS TERMINATED BY ';'
        (tk             INTEGER,
         title          CHAR,
         text_file      FILLER CHAR,
         text           LOBFILE(text_file) TERMINATED BY EOF)

A.2.3.2 loader.dat

この例では、loader.datファイルのサンプルを示します。各行は、3つのフィールド(ドキュメントの参照番号、ラベル(すなわちタイトル)、およびsearch_tableのテキスト列にロードされるHTMLドキュメント名)で構成されます。この例では、ファイルは切り捨てられています。

1;   Pizza Shredder;Pizza.html
2;   Refrigerator w/ Front-Door Auto Cantaloupe Dispenser;Cantaloupe.html
3;   Self-Tipping Couch;Couch.html
4;   Home Air Dirtier;Mess.html
5;   Set of Pet Magnets;Pet.html
6;   Esteem-Building Talking Pillow;Snooze.html
      . . .
28;   Shaggy Found Inspiration For Success In Jamaica ;shaggy_found.html
29;   Solar Flare Eruptions Likely ;solar_flare.html
30;   Supersonic Plane Breaks Food Barrier ;food_barrier.html
31;   SOUNDSCAN REPORT: Recipe for An Aspiring Top Ten;urban_groove_1.html
      . . .

A.2.3.3 search_htmlservices.sql

set define off
create or replace package search_htmlServices as
  procedure showHTMLDoc (p_id in numeric);
  procedure showDoc  (p_id in varchar2, p_query in varchar2);
end;
/
show errors;

create or replace package body search_htmlServices as

  procedure showHTMLDoc (p_id in numeric) is
    v_clob_selected   CLOB;
    v_read_amount     integer;
    v_read_offset     integer;
    v_buffer          varchar2(32767);
   begin


     select text into v_clob_selected from search_table where tk = p_id;
     v_read_amount := 32767;
     v_read_offset := 1;
   begin
    loop
      dbms_lob.read(v_clob_selected,v_read_amount,v_read_offset,v_buffer);
      htp.print(v_buffer);
      v_read_offset := v_read_offset + v_read_amount;
      v_read_amount := 32767;
    end loop;
   exception
   when no_data_found then
     null;
   end;
 end showHTMLDoc;


procedure showDoc (p_id in varchar2, p_query in varchar2) is

 v_clob_selected   CLOB;
 v_read_amount     integer;
 v_read_offset     integer;
 v_buffer          varchar2(32767);
 v_query           varchar(2000);
 v_cursor          integer;

 begin
   htp.p('<html><title>HTML version with highlighted terms</title>');
   htp.p('<body bgcolor="#ffffff">');
   htp.p('<b>HTML version with highlighted terms</b>');

   begin
     ctx_doc.markup (index_name => 'idx_search_table',
                     textkey    => p_id,
                     text_query => p_query,
                     restab     => v_clob_selected,
                     starttag   => '<i><font color=red>',
                     endtag     => '</font></i>');

     v_read_amount := 32767;
     v_read_offset := 1;
     begin
      loop
        dbms_lob.read(v_clob_selected,v_read_amount,v_read_offset,v_buffer);
        htp.print(v_buffer);
        v_read_offset := v_read_offset + v_read_amount;
        v_read_amount := 32767;
      end loop;
     exception
      when no_data_found then
         null;
     end;

     exception
      when others then
        null; --showHTMLdoc(p_id);
   end;
end showDoc;
end;
/
show errors


set define on

A.2.3.4 search_html.psp

<%@ plsql procedure="search_html" %>
<%@ plsql parameter="query" default="null" %>
<%! v_results numeric := 0; %>

<html>
<head>
  <title>search_html Search </title>
</head>
<body>

<%

If query is null Then
%>

  <center>
    <form method=post action="search_html">
     <b>Search for: </b>
     <input type=text name="query" size=30>&nbsp;
     <input type=submit value=Search>
  </center>
<hr>

<% 
  Else
%>

   <p>
   <%!
      color varchar2(6) := 'ffffff';
   %>

   <center>
     <form method=post action="search_html">
      <b>Search for:</b>
      <input type=text name="query" size=30 value="<%= query %>">
      <input type=submit value=Search>
     </form>
   </center>
   <hr>
   <p>

   <%
     -- select statement 
    for doc in (
                select /*+ DOMAIN_INDEX_SORT */ rowid, tk, title, score(1) scr
                from search_table
                where contains(text, query,1) >0
                order by score(1) desc
               ) 
         loop
           v_results := v_results + 1;
           if v_results = 1 then

   %>

             <center>
              <table border="0">
                <tr bgcolor="#6699CC">
                  <th>Score</th>
                  <th>Title</th>
                </tr>

  <%      end if; %>
          <tr bgcolor="#<%= color %>">
           <td> <%= doc.scr %>% </td>
           <td> <%= doc.title %>
           [<a href="search_htmlServices.showHTMLDoc?p_id=
                  <%= doc.tk %>">HTML</a>]
           [<a href="search_htmlServices.showDoc?p_id=
                  <%= doc.tk %>&p_query=<%= query %>">Highlight</a>]
           </td>
         </tr>

   <%
          if (color = 'ffffff') then
               color := 'eeeeee';
             else
               color := 'ffffff';
          end if;

     end loop; 
   %>

    </table>
   </center>

<% 
  end if;
%>
</body></html>

A.3 JSP Webアプリケーション

JSPベースのWebアプリケーションの作成は、PSPベースのアプリケーションの作成とほぼ同じ手順で行われます(「Webアプリケーションの作成」を参照してください)。同じloader.datファイルおよびloader.ctlファイルを使用できます。ただし、JSPベースのアプリケーションでは、次のことは不要です。

  • search_htmlservicesパッケージのコンパイル

  • search_htmlのPSPページのコンパイル(loadpspを使用)

A.3.1 Webアプリケーションの前提条件

このアプリケーションには、次の要件があります。

  • Oracle Database(リリース8.1.6以上)が起動され、実行中であること。

  • ApacheなどのWebサーバーが起動され、実行中であり、Oracle Databaseに要求を送信するように適切に構成されていること。

A.3.2 JSPのサンプル・コード

この項では、Webアプリケーションのサンプルの作成に使用するJavaコードを示します。次のファイルを記載しています。

  • search_html.jsp

    このファイルのコードは、テキスト問合せアプリケーション・ウィザードで生成されました。(長い行の一部は、コードが読み取りやすいように分割されました。)

A.3.2.1 search_html.jsp

<%@ page import="java.sql.*, java.util.*, java.net.*, 
   oracle.jdbc.*, oracle.jsp.dbutil.*" %>
<%@ page contentType="text/html;charset=UTF-8" %>
<% oracle.jsp.util.PublicUtil.setReqCharacterEncoding(request, "UTF-8"); %>
<jsp:useBean id="name" class="oracle.jsp.jml.JmlString" scope ="request" >
<jsp:setProperty name="name" property="value" param="query" />
</jsp:useBean>
 
<%
String connStr="jdbc:oracle:thin:@jsmith-pc.us.oracle.com:1521:zippy922";
 
java.util.Properties info=new java.util.Properties();
Connection conn = null;
ResultSet rset = null;
OracleCallableStatement callStmt = null;
Statement stmt = null;
String userQuery = null;
String myQuery = null;
URLEncoder myEncoder;
int count=0;
int loopNum=0;
int startNum=0;
if (name.isEmpty()) {
%>
  <html>
    <title>Text Search</title>
    <body>
      <table width="100%">
        <tr bgcolor="#336699">
          <td><font face="arial, helvetica" align="left" 
          color="#CCCC99" size=+2>Text Search</td>
        </tr>
      </table>
    <center>
      <form method = post>
      Search for:
      <input type=text name=query size = 30>
      <input type=submit value="Search">
      </form>
    </center>
    </body>
  </html>
 
<%}
 
else {
%>
  <html>
    <title>Text Search</title>
    <body text="#000000" bgcolor="#FFFFFF" link="#663300" 
          vlink="#996633" alink="#ff6600">
      <table width="100%">
        <tr bgcolor="#336699">
          <td><font face="arial, helvetica" align="left" 
                 color="#CCCC99" size=+2>Text Search</td>
        </tr>
      </table>
    <center>
      <form method = post action="TextSearchApp.jsp">
      Search for:
      <input type=text name="query" value="<%=name.getValue() %>" size = 30>
      <input type=submit value="Search">
      </form>
    </center>
<%
  try {
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver() );
    info.put ("user", "jsmith");
    info.put ("password","hello");
    conn = DriverManager.getConnection(connStr,info);
    stmt = conn.createStatement();
    userQuery =   request.getParameter("query");
    myQuery =   URLEncoder.encode(userQuery);
    String numStr =   request.getParameter("sn");
    if(numStr!=null)
      startNum=Integer.parseInt(numStr);
    String theQuery =   translate(userQuery);
    callStmt =(OracleCallableStatement)conn.prepareCall("begin "+
         "?:=ctx_query.count_hits(index_name=>'ULTRA_IDX1', "+
         "text_query=>?"+
         "); " +
         "end; ");
    callStmt.setString(2,theQuery);
    callStmt.registerOutParameter(1, OracleTypes.NUMBER);
    callStmt.execute();
    count=((OracleCallableStatement)callStmt).getNUMBER(1).intValue();
    if(count>=(startNum+20)){
%>
    <font color="#336699" FACE="Arial,Helvetica" SIZE=+1>Results
           <%=startNum+1%> - <%=startNum+20%> of <%=count%> matches
<%
    }
    else if(count>0){
%>
    <font color="#336699" FACE="Arial,Helvetica" SIZE=+1>Results
           <%=startNum+1%> - <%=count%> of <%=count%> matches
<%
    }
    else {
%>
    <font color="#336699" FACE="Arial,Helvetica" SIZE=+1>No match found
<%
    }
%>
  <table width="100%">
  <TR ALIGN="RIGHT">
<%
  if((startNum>0)&(count<=startNum+20))
  {
%>
    <TD ALIGN="RIGHT">
    <a href="TextSearchApp.jsp?sn=<%=startNum-20 %>&query=
            <%=myQuery %>">previous20</a>
    </TD>
<%
  }
  else if((count>startNum+20)&(startNum==0))
  {
%>
    <TD ALIGN="RIGHT">
    <a href="TextSearchApp.jsp?sn=<%=startNum+20 
          %>&query=<%=myQuery %>">next20</a>
    </TD>
<%
  }
  else if((count>startNum+20)&(startNum>0))
  {
%>
    <TD ALIGN="RIGHT">
    <a href="TextSearchApp.jsp?sn=<%=startNum-20 %>&query=
              <%=myQuery %>">previous20</a>
    <a href="TextSearchApp.jsp?sn=<%=startNum+20 %>&query=
              <%=myQuery %>">next20</a>
    </TD>
<%
  }
%>
  </TR>
  </table>
<%
    String ctxQuery = "select /*+ DOMAIN_INDEX_SORT */ rowid, 'TITLE',
     score(1) scr from 'ULTRA_TAB1' where contains('TEXT', '"+theQuery+"',1 )
     > 0 order by score(1) desc";
    rset = stmt.executeQuery(ctxQuery);
    String color = "ffffff";
    String rowid = null;
    String fakeRowid = null;
    String[] colToDisplay = new String[1];
    int myScore = 0;
    int items = 0;
    while (rset.next()&&items< 20) {
      if(loopNum>=startNum)
      {
        rowid = rset.getString(1);
        fakeRowid = URLEncoder.encode(rowid);
        colToDisplay[0] = rset.getString(2);
        myScore = (int)rset.getInt(3);
        items++;
        if (items == 1) {
%>
        <center>
          <table BORDER=1 CELLSPACING=0 CELLPADDING=0 width="100%"
            <tr bgcolor="#CCCC99">
              <th><font face="arial, helvetica" color="#336699">Score</th>
              <th><font face="arial, helvetica" color="#336699">TITLE</th>
              <th> <font face="arial, helvetica" 
                       color="#336699">Document Services</th>
            </tr>
<%   } %>
      <tr bgcolor="#FFFFE0">
        <td ALIGN="CENTER"> <%= myScore %>%</td>
        <td> <%= colToDisplay[0] %>
        <td>
        </td>
      </tr>
<%
      if (color.compareTo("ffffff") == 0)
        color = "eeeeee";
      else
        color = "ffffff";
      }
      loopNum++;
    }
} catch (SQLException e) {
%>
    <b>Error: </b> <%= e %><p>
<%
} finally {
  if (conn != null) conn.close();
  if (stmt != null) stmt.close();
  if (rset != null) rset.close();
  }
%>
  </table>
  </center>
  <table width="100%">
  <TR ALIGN="RIGHT">
<%
  if((startNum>0)&(count<=startNum+20))
  {
%>
    <TD ALIGN="RIGHT">
    <a href="TextSearchApp.jsp?sn=<%=startNum-20 %>&query=
               <%=myQuery %>">previous20</a>
    </TD>
<%
  }
  else if((count>startNum+20)&(startNum==0))
  {
%>
    <TD ALIGN="RIGHT">
    <a href="TextSearchApp.jsp?sn=<%=startNum+20 %>&query=
          <%=myQuery %>">next20</a>
    </TD>
<%
  }
  else if((count>startNum+20)&(startNum>0))
  {
%>
    <TD ALIGN="RIGHT">
    <a href="TextSearchApp.jsp?sn=<%=startNum-20 %>&query=
          <%=myQuery %>">previous20</a>
    <a href="TextSearchApp.jsp?sn=<%=startNum+20 %>&query=
          <%=myQuery %>">next20</a>
    </TD>
<%
  }
%>
  </TR>
  </table>
  </body></html>
<%}
 
%>
<%!
   public String translate (String input)
   {
      Vector reqWords = new Vector();
      StringTokenizer st = new StringTokenizer(input, " '", true);
      while (st.hasMoreTokens())
      {
        String token = st.nextToken();
        if (token.equals("'"))
        {
           String phrase = getQuotedPhrase(st);
           if (phrase != null)
           {
              reqWords.addElement(phrase);
           }
        }
        else if (!token.equals(" "))
        {
           reqWords.addElement(token);
        }
      }
      return getQueryString(reqWords);
   }
 
   private String getQuotedPhrase(StringTokenizer st)
   {
      StringBuffer phrase = new StringBuffer();
      String token = null;
      while (st.hasMoreTokens() && (!(token = st.nextToken()).equals("'")))
      {
        phrase.append(token);
      }
      return phrase.toString();
   }
 
 
   private String getQueryString(Vector reqWords)
   {
      StringBuffer query = new StringBuffer("");
      int length = (reqWords == null) ? 0 : reqWords.size();
      for (int ii=0; ii < length; ii++)
      {
         if (ii != 0)
         {
           query.append(" & ");
         }
         query.append("{");
         query.append(reqWords.elementAt(ii));
         query.append("}");
      }
      return query.toString();
   }
%>