1

Oracle Text の全文検索機能を容易にするために、1 つの列で ctxsys.context 索引を使用しています。しかし、',' または '.' で区切られた数値をインデックス化するときに問題が発生します。

次のようなインデックスを作成しました。

create index my_index on my_table(my_column)
indextype is ctxsys.context parameters ('SYNC (ON COMMIT)');

次に、4 つのテキスト ドキュメントを挿入します。

insert into my_table (id, doc) values (1, 'FOO 300 BAR');
insert into my_table (id, doc) values (2, 'FOO 300 BAR 1,000.00');
insert into my_table (id, doc) values (3, 'FOO1FOO');
insert into my_table (id, doc) values (4, '1 FOO');

ここで、contains 演算子を使用して、「FOO 300 BAR」、「1,000.00」、および両方の組み合わせを検索したいと思います。

select score(1), id from my_table where contains(doc, 'FOO 300 BAR', 1) > 0;
select score(1), id from my_table where contains(doc, '1,000.00', 1) > 0;
select score(1), id from my_table where contains(doc, 'FOO 300 BAR 1,000.00', 1) > 0;

最初のものは期待どおりに機能し、結果として id 1 と 2 の両方を取得します。1,000.00 を使用しようとすると、結果として 0 行が得られます。

ドキュメントから読んだように、デフォルトとして BASIC_LEXER を使用しています。また、レクサーでセパレーターを明示的に指定して、それをインデックスに適用しようとしました。

begin
ctx_ddl.create_preference('my_lex', 'BASIC_LEXER');
ctx_ddl.set_attribute('my_lex', 'numjoin', '.');
ctx_ddl.set_attribute('my_lex', 'numgroup', ',');
end;

create index my_index on my_table(doc)
indextype is ctxsys.context parameters ('SYNC (ON COMMIT) LEXER my_lex');

しかし、私は以前と同じ行動を経験しました。

Oracle Textがセパレータ付きの数字をどのように処理するか、および区切られた数字が単一の単語として扱われるように索引を構成する方法を説明してもらえますか?

Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production を使用しています

4

1 に答える 1

1

私は Oracle 10g を使用していますが、あなたが説明したのと同じ問題がありましたが、わずかな違いが 1 つあります。

私はこのスクリプトを使用しました:

    begin
      ctx_ddl.create_preference('my_lexer', 'BASIC_LEXER');
      ctx_ddl.set_attribute('my_lexer', 'numjoin', '.');
      ctx_ddl.set_attribute('my_lexer', 'numgroup', ','); 
      ctx_ddl.set_attribute('my_lexer', 'printjoins', '-/"_'); 
      ctx_ddl.set_attribute('my_lexer', 'index_text', 'YES'); 

    end;

そして、これはインデックスを作成します:

Create Index my_table_TIX01 ON my_table (doc) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS('lexer my_lexer SYNC (ON COMMIT)')

私の場合、このクエリは1行を返します。

select score(1), id, doc from my_table where contains(doc, '1,000.00', 1) > 0;

SCORE(1),ID,DOC
2,4,1 FOO

問題は、検索する文字列内のトークンがどのように解析されるかです。基本的に 1,000.00 は複数のトークンに分割されます: 1 の次に 000.00 です。次の行を挿入して、これを試すことができます。

insert into my_table (id, doc) values (5, '00 FOO');
insert into my_table (id, doc) values (6, '000.00 FOO');
commit; -- Dont' forget to commit the data you insert otherwise the index is not updated!

次に、次のクエリを実行します。

select score(1), id, doc from my_table where contains(doc, '1,000.00', 1) > 0;

次のように返されます。

SCORE(1),ID,DOC
3,4,1 FOO
3,6,000.00 FOO

コンマは ACCUM と同じです。これはドキュメントからのものです(下部のリンクを参照してください):

ACCUM 、 ACCUM 演算子を使用して、クエリ用語のいずれかが少なくとも 1 回出現するドキュメントを検索します。Accumulate 演算子は、ドキュメントの用語の重みの合計に従ってドキュメントをランク付けします。次のクエリは、dogs、cats、および puppies という用語を含むすべてのドキュメントを返し、3 つの用語すべてを含むドキュメントに最高のスコアを与えます。

「犬、猫、子犬」

検索を修正するには、検索する文字列を中括弧で囲む必要があります。

これら 2 つのクエリは、期待どおりのデータを返します。

select score(1), id, doc from my_table where contains(doc, '{1,000.00}', 1) > 0;
select score(1), id, doc from my_table where contains(doc, 'FOO 300 BAR {1,000.00}', 1) > 0;

もう 1 つ注意すべき点は、300 FOO を検索する場合、つまり次のクエリを実行することです。

select score(1), id, doc from my_table where contains(doc, '300 FOO', 1) > 0;

何も返ってきません。リラクゼーション テンプレートを使用するか、AND または & を使用する必要があります。例:

select score(1), id, doc from my_table where contains(doc, '300 and FOO', 1) > 0;

select score(1), id, doc from my_table where contains(doc, '
    <query>
       <textquery lang="ENGLISH" grammar="CONTEXT">
         <progression>
           <seq>300 f00</seq>
           <seq>300 NEAR f00</seq>
           <seq>300 AND foo</seq>       
         </progression>
       </textquery>
       <score datatype="INTEGER" algorithm="COUNT"/>
    </query>
    ', 1) > 0; 

次のリンクも参照してください。

私たちはGoogleの検索に非常に慣れていると思いますが、これはGoogleとまったく同じようには機能しません...

于 2014-06-26T05:44:17.700 に答える