apeescape2.com
  • メイン
  • 収益性と効率性
  • Uxデザイン
  • プロセスとツール
  • エンジニアリング管理
バックエンド

Apache Luceneとのダイアログの全文検索:チュートリアル

Apache Lucene は、ドキュメントの全文検索に使用されるJavaライブラリであり、次のような検索サーバーの中核です。 Solr そして Elasticsearch 。また、AndroidアプリやWebバックエンドなどのJavaアプリケーションに埋め込むこともできます。

Luceneの構成オプションは豊富ですが、 データベース開発者 テキストの一般的なコーパス。ドキュメントに特定の構造またはコンテンツの種類がある場合は、どちらかを利用して検索品質とクエリ機能を向上させることができます。

apacheluceneによる全文検索



この種のカスタマイズの例として、このLuceneチュートリアルでは、のコーパスにインデックスを付けます。 プロジェクトグーテンベルク 、何千もの無料の電子書籍を提供しています。これらの本の多くは小説であることを私たちは知っています。私たちが特に興味を持っているとしましょう 対話 これらの小説の中で。 Lucene、Elasticsearch、Solrのいずれも、コンテンツをダイアログとして識別するためのすぐに使用できるツールを提供していません。実際、テキスト分析の初期段階で句読点を破棄します。これは、会話であるテキストの部分を識別できることに反します。したがって、カスタマイズを開始する必要があるのは、これらの初期段階です。

ApacheLucene分析パイプラインの一部

ザ・ Lucene分析JavaDoc テキスト分析パイプラインのすべての可動部分の概要を提供します。

大まかに言えば、分析パイプラインは、最初に文字の生のストリームを消費し、最後に単語にほぼ対応する「用語」を生成するものと考えることができます。

標準の分析パイプラインは 視覚化 など:

Lucene分析パイプライン

このパイプラインをカスタマイズして、二重引用符でマークされたテキストの領域を認識する方法を説明します。これをダイアログと呼び、それらの領域で検索するときに発生する一致を増やします。

文字を読む

ドキュメントが最初にインデックスに追加されるとき、文字はJavaから読み取られます InputStream 、およびファイル、データベース、Webサービス呼び出しなどから取得できます。ProjectGutenbergのインデックスを作成するには、電子書籍をダウンロードし、これらのファイルを読み取ってインデックスに書き込む小さなアプリケーションを作成します。 Luceneインデックスの作成とファイルの読み取りはよく行われているため、あまり詳しく説明しません。インデックスを作成するための重要なコードは次のとおりです。

IndexWriter writer = ...; BufferedReader reader = new BufferedReader(new InputStreamReader(... fileInputStream ...)); Document document = new Document(); document.add(new StringField('title', fileName, Store.YES)); document.add(new TextField('body', reader)); writer.addDocument(document);

各電子書籍が単一のLuceneに対応することがわかりますDocumentしたがって、後で、検索結果は一致する本のリストになります。 Store.YESを保存することを示します 題名 フィールド。これは単なるファイル名です。保存したくない 体 ただし、検索時に必要ではなく、ディスク領域を浪費するだけなので、電子書籍の

ストリームの実際の読み取りはaddDocumentで始まります。 IndexWriterパイプラインの最後からトークンをプルします。このプルは、最初のステージであるTokenizerがInputStreamから読み取るまでパイプを介して戻ります。

Luceneがこれを処理するため、ストリームを閉じないことにも注意してください。

文字のトークン化

Lucene StandardTokenizer 句読点を破棄するため、引用符を保持する必要があるため、ここからカスタマイズを開始します。

StandardTokenizerのドキュメントソースコードをコピーしてニーズに合わせて調整することをお勧めしますが、このソリューションは不必要に複雑になります。代わりに、CharTokenizerを拡張します。これにより、「受け入れる」文字を指定できます。「受け入れ」されない文字は、トークン間の区切り文字として扱われ、破棄されます。単語とその周囲の引用符に関心があるため、カスタムTokenizerは次のようになります。

public class QuotationTokenizer extends CharTokenizer { @Override protected boolean isTokenChar(int c) return Character.isLetter(c) }

[He said, 'Good day'.]の入力ストリームが与えられると、生成されるトークンは[He]、[said]、['Good]、[day']になります。

C ++のガイド

引用符がトークン内にどのように散在しているかに注意してください。 Tokenizerを書くことができます引用ごとに別々のトークンを生成しますが、Tokenizerまた、バッファリングやスキャンなど、面倒でねじ込みやすい詳細にも関心があるため、Tokenizerを保持することをお勧めします。単純で、パイプラインのさらに先のトークンストリームをクリーンアップします。

フィルタを使用したトークンの分割

トークナイザーの後に一連のTokenFilterがありますオブジェクト。ちなみに、 フィルタ TokenFilterのように、少し誤解されていますトークンを追加、削除、または変更できます。

Luceneが提供するフィルタークラスの多くは単一の単語を想定しているため、単語と引用符が混在するトークンがそれらに流れ込むことはありません。したがって、Luceneチュートリアルの次のカスタマイズは、QuotationTokenizerの出力をクリーンアップするフィルターの導入である必要があります。

このクリーンアップには、追加の生成が含まれます 見積もりを開始 引用符が単語の先頭にある場合はトークン、または 見積もり終了 引用符が最後に表示されている場合はトークン。簡単にするために、一重引用符で囲まれた単語の処理は脇に置きます。

TokenFilterの作成サブクラスには、incrementTokenという1つのメソッドの実装が含まれます。このメソッドはincrementTokenを呼び出す必要がありますパイプ内の前のフィルターで、その呼び出しの結果を操作して、フィルターが担当するすべての作業を実行します。 incrementTokenの結果Attributeから入手できますトークン処理の現在の状態を説明するオブジェクト。 incrementTokenの実装後が返される場合、次のフィルター(またはパイプの最後にいる場合はインデックス)のトークンを設定するために属性が操作されていることが期待されます。

パイプラインのこの時点で関心のある属性は次のとおりです。

  • CharTermAttribute:char[]が含まれています現在のトークンの文字を保持するバッファ。見積もりを削除するか、見積もりトークンを生成するには、これを操作する必要があります。

  • TypeAttribute:現在のトークンの「タイプ」が含まれます。トークンストリームに開始引用符と終了引用符を追加しているため、フィルターを使用して2つの新しいタイプを導入します。

  • OffsetAttribute:Luceneは、オプションで、元のドキュメント内の用語の場所への参照を保存できます。これらの参照は「オフセット」と呼ばれ、元の文字ストリームへの開始インデックスと終了インデックスにすぎません。 CharTermAttributeのバッファを変更した場合トークンの部分文字列のみを指すには、それに応じてこれらのオフセットを調整する必要があります。

トークンストリームを操作するためのAPIがなぜそれほど複雑なのか、特に、なぜString#splitのようなことを実行できないのか疑問に思われるかもしれません。着信トークンに。これは、Luceneが高速でオーバーヘッドの少ないインデックス作成用に設計されているためです。これにより、組み込みのトークナイザーとフィルターは、メガバイトのメモリのみを使用しながら、ギガバイトのテキストをすばやく処理できます。これを実現するために、トークン化とフィルタリング中に割り当てがほとんどまたはまったく行われないため、Attribute上記のインスタンスは、一度割り当てて再利用することを目的としています。トークナイザーとフィルターがこのように記述されていて、それら自体の割り当てを最小限に抑えると、パフォーマンスを損なうことなくLuceneをカスタマイズできます。

これらすべてを念頭に置いて、['Hello]などのトークンを受け取り、2つのトークン[']を生成するフィルターを実装する方法を見てみましょう。および[Hello]:

public class QuotationTokenFilter extends TokenFilter { private static final char QUOTE = '''; public static final String QUOTE_START_TYPE = 'start_quote'; public static final String QUOTE_END_TYPE = 'end_quote'; private final OffsetAttribute offsetAttr = addAttribute(OffsetAttribute.class); private final TypeAttribute typeAttr = addAttribute(TypeAttribute.class); private final CharTermAttribute termBufferAttr = addAttribute(CharTermAttribute.class);

最初に、以前に見た属性のいくつかへの参照を取得します。フィールド名には「Attr」という接尾辞を付けて、後で参照するときに明確になるようにします。いくつかのTokenizerが可能です実装はこれらの属性を提供しないため、addAttributeを使用します私たちの参照を取得します。 addAttribute欠落している場合は属性インスタンスを作成し、それ以外の場合はそのタイプの属性への共有参照を取得します。 Luceneでは、同じ属性タイプの複数のインスタンスを一度に許可しないことに注意してください。

private boolean emitExtraToken; private int extraTokenStartOffset, extraTokenEndOffset; private String extraTokenType;

フィルタは元のストリームに存在しなかった新しいトークンを導入するため、incrementTokenの呼び出しの間にそのトークンの状態を保存する場所が必要です。既存のトークンを2つに分割しているため、新しいトークンのオフセットとタイプだけを知っていれば十分です。 incrementTokenへの次の呼び出しかどうかを示すフラグもありますこの追加のトークンを発行します。 Luceneは、実際には2つのメソッドcaptureStateを提供しています。およびrestoreStateは、これを行います。ただし、これらの方法には、Stateの割り当てが含まれます。オブジェクトであり、実際にはその状態を自分で管理するよりも難しい場合があるため、それらの使用は避けます。

@Override public void reset() throws IOException { emitExtraToken = false; extraTokenStartOffset = -1; extraTokenEndOffset = -1; extraTokenType = null; super.reset(); }

Luceneは、割り当てを積極的に回避する一環として、フィルターインスタンスを再利用できます。この状況では、resetへの呼び出しが予想されます。フィルタを初期状態に戻します。したがって、ここでは、追加のトークンフィールドをリセットするだけです。

@Override public boolean incrementToken() throws IOException { if (emitExtraToken) { advanceToExtraToken(); emitExtraToken = false; return true; } ...

今、私たちは興味深い部分に到達しています。 incrementTokenの実装時と呼ばれる、私たちはする機会があります ない 電話incrementTokenパイプラインの初期段階で。そうすることで、Tokenizerからトークンを取得しないため、新しいトークンを効果的に導入します。

代わりに、advanceToExtraTokenと呼びます追加のトークンの属性を設定するには、emitExtraTokenを設定します次の呼び出しでこの分岐を回避するにはfalseに設定し、trueを返します。これは、別のトークンが使用可能であることを示します。

@Override public boolean incrementToken() throws IOException { ... (emit extra token) ... boolean hasNext = input.incrementToken(); if (hasNext) { char[] buffer = termBufferAttr.buffer(); if (termBuffer.length() > 1) { if (buffer[0] == QUOTE) { splitTermQuoteFirst(); } else if (buffer[termBuffer.length() - 1] == QUOTE) { splitTermWordFirst(); } } else if (termBuffer.length() == 1) { if (buffer[0] == QUOTE) { typeAttr.setType(QUOTE_END_TYPE); } } } return hasNext; }

incrementTokenの残りの部分3つの異なることのいずれかを実行します。 termBufferAttrを思い出してくださいパイプを通過するトークンの内容を検査するために使用されます。

  1. トークンストリームの最後に到達した場合(つまり、hasNextがfalseの場合)、完了して単純に戻ります。

  2. 複数の文字のトークンがあり、それらの文字の1つが引用符である場合、トークンを分割します。

  3. トークンが単独引用符である場合、それは終了引用符であると見なされます。理由を理解するために、開始引用符は常に単語の左側に表示されますが(つまり、中間句読点はありません)、終了引用符は句読点の後に続けることができます(文のように[He told us to 'go back the way we came.'])。このような場合、終了引用符はすでに別のトークンになっているため、そのタイプを設定するだけで済みます。

splitTermQuoteFirstおよびsplitTermWordFirst現在のトークンを単語または引用符にするための属性を設定し、残りの半分を後で消費できるように「追加」フィールドを設定します。 2つの方法は似ているので、splitTermQuoteFirstだけを見ていきます。

Googleスプレッドシートでマクロを使用する
private void splitTermQuoteFirst() { int origStart = offsetAttr.startOffset(); int origEnd = offsetAttr.endOffset(); offsetAttr.setOffset(origStart, origStart + 1); typeAttr.setType(QUOTE_START_TYPE); termBufferAttr.setLength(1); prepareExtraTerm(origStart + 1, origEnd, TypeAttribute.DEFAULT_TYPE); }

このトークンを分割して、最初に引用符がストリームに表示されるようにするため、長さを1(つまり、1文字、つまり引用符)に設定してバッファーを切り捨てます。それに応じてオフセットを調整し(つまり、元のドキュメントの引用符を指す)、タイプを開始引用符に設定します。

prepareExtraTerm extra*を設定しますフィールドとセットemitExtraToken本当に。これは、「余分な」トークン(つまり、引用符に続く単語)を指すオフセットで呼び出されます。

QuotationTokenFilterの全体です GitHubで入手可能 。

余談ですが、このフィルターは1つの追加トークンしか生成しませんが、このアプローチを拡張して、任意の数の追加トークンを導入できます。 extra*を置き換えるだけですコレクションを持つフィールド、または生成できる追加のトークンの数に制限がある場合は固定長の配列。見る SynonymFilter とそのPendingInputこの例の内部クラス。

見積もりトークンの消費とマーキングダイアログ

これらの引用符をトークンストリームに追加するためのすべての努力を行ったので、それらを使用してテキスト内のダイアログのセクションを区切ることができます。

最終目標は、用語がダイアログの一部であるかどうかに基づいて検索結果を調整することであるため、それらの用語にメタデータを添付する必要があります。 LuceneはPayloadAttributeを提供しますこの目的のために。ペイロードは、インデックス内の用語と一緒に格納されるバイト配列であり、後で検索中に読み取ることができます。これは、フラグが1バイト全体を無駄に占有することを意味するため、スペースを節約するために追加のペイロードをビットフラグとして実装できます。

以下は、分析パイプラインの最後に追加される新しいフィルターDialoguePayloadTokenFilterです。トークンがダイアログの一部であるかどうかを示すペイロードを添付します。

public class DialoguePayloadTokenFilter extends TokenFilter { private final TypeAttribute typeAttr = getAttribute(TypeAttribute.class); private final PayloadAttribute payloadAttr = addAttribute(PayloadAttribute.class); private static final BytesRef PAYLOAD_DIALOGUE = new BytesRef(new byte[] { 1 }); private static final BytesRef PAYLOAD_NOT_DIALOGUE = new BytesRef(new byte[] { 0 }); private boolean withinDialogue; protected DialoguePayloadTokenFilter(TokenStream input) { super(input); } @Override public void reset() throws IOException { this.withinDialogue = false; super.reset(); } @Override public boolean incrementToken() throws IOException { boolean hasNext = input.incrementToken(); while(hasNext) { boolean isStartQuote = QuotationTokenFilter .QUOTE_START_TYPE.equals(typeAttr.type()); boolean isEndQuote = QuotationTokenFilter .QUOTE_END_TYPE.equals(typeAttr.type()); if (isStartQuote) { withinDialogue = true; hasNext = input.incrementToken(); } else if (isEndQuote) { withinDialogue = false; hasNext = input.incrementToken(); } else { break; } } if (hasNext) { payloadAttr.setPayload(withinDialogue ? PAYLOAD_DIALOGUE : PAYLOAD_NOT_DIALOGUE); } return hasNext; } }

このフィルターは単一の状態withinDialogueを維持するだけでよいので、はるかに簡単です。開始引用符は、ダイアログのセクション内にいることを示し、終了引用符は、ダイアログのセクションが終了したことを示します。いずれの場合も、引用トークンはincrementTokenを2回呼び出すことで破棄されるため、事実上、 見積もりを開始 または 見積もり終了 トークンがパイプラインのこの段階を通過することはありません。

たとえば、DialoguePayloadTokenFilterトークンストリームを変換します:

[the], [program], [printed], ['], [hello], [world], [']`

この新しいストリームに:

[the][0], [program][0], [printed][0], [hello][1], [world][1]

トークナイザーとフィルターを結び付ける

Analyzer通常はTokenizerを組み合わせて、分析パイプラインを組み立てます。一連のTokenFilter sを使用します。 Analyzer sは、そのパイプラインが分析間でどのように再利用されるかを定義することもできます。コンポーネントはreset()の呼び出し以外は何も必要としないため、これについて心配する必要はありません。 Luceneが常に行う使用の合間に。 Analyzer#createComponents(String)を実装してアセンブリを実行する必要があります。

public class DialogueAnalyzer extends Analyzer { @Override protected TokenStreamComponents createComponents(String fieldName) { QuotationTokenizer tokenizer = new QuotationTokenizer(); TokenFilter filter = new QuotationTokenFilter(tokenizer); filter = new LowerCaseFilter(filter); filter = new StopFilter(filter, StopAnalyzer.ENGLISH_STOP_WORDS_SET); filter = new DialoguePayloadTokenFilter(filter); return new TokenStreamComponents(tokenizer, filter); } }

前に見たように、フィルターにはパイプラインの前のステージへの参照が含まれているため、フィルターをインスタンス化する方法です。また、StandardAnalyzerからいくつかのフィルターをスライドさせます:LowerCaseFilterおよびStopFilter。これらの2つはQuotationTokenFilterの後に来る必要があります引用符が分離されていることを確認します。 DialoguePayloadTokenFilterの後のどこにでもあるので、QuotationTokenFilterの配置をより柔軟にすることができます。しましょう。 StopFilterの後に置きますダイアログペイロードをに注入する時間を無駄にしないため ストップワード 最終的には削除されます。

これは、動作中の新しいパイプラインの視覚化です(削除した、またはすでに見た標準パイプラインの部分を除く)。

apacheluceneでの新しいパイプラインの視覚化

DialogueAnalyzer他のストックと同じように使用できるようになりましたAnalyzerこれで、インデックスを作成して検索に進むことができます。

対話の全文検索

ダイアログのみを検索したい場合は、引用符の外にあるすべてのトークンを単に破棄するだけで済みます。代わりに、元のトークンをすべてそのままにしておくことで、会話を考慮したクエリを実行したり、会話をテキストの他の部分と同じように扱ったりする柔軟性を確保しました。

Excel用のpowerpivotとは

Luceneインデックスのクエリの基本は次のとおりです。 十分に文書化されている 。私たちの目的では、クエリがTermで構成されていることを知っていれば十分です。 MUSTなどの演算子で結合されたオブジェクトまたはSHOULD、およびそれらの用語に基づく一致ドキュメント。一致するドキュメントは、構成可能なSimilarityに基づいてスコアリングされます。オブジェクト、およびそれらの結果は、スコア順に並べ替えたり、フィルタリングしたり、制限したりできます。たとえば、Luceneでは、両方の用語[hello]を含む必要がある上位10個のドキュメントに対してクエリを実行できます。および[world]。

ダイアログに基づいて検索結果をカスタマイズするには、ペイロードに基づいてドキュメントのスコアを調整します。このための最初の拡張ポイントはSimilarityにあり、一致する用語の重み付けとスコアリングを担当します。

類似性とスコアリング

クエリは、デフォルトでDefaultSimilarityを使用します。これは、ドキュメント内で発生する頻度に基づいて用語に重みを付けます。重みを調整するための優れた拡張ポイントであるため、ペイロードに基づいてドキュメントをスコアリングするためにも拡張します。メソッドDefaultSimilarity#scorePayloadこの目的のために提供されています:

public final class DialogueAwareSimilarity extends DefaultSimilarity { @Override public float scorePayload(int doc, int start, int end, BytesRef payload) { if (payload.bytes[payload.offset] == 0) { return 0.0f; } return 1.0f; } }

DialogueAwareSimilarity単に非ダイアログペイロードをゼロとしてスコアリングします。それぞれとしてTerm複数回一致させることができ、複数のペイロードスコアを持つ可能性があります。 Queryまでのこれらのスコアの解釈実装。

BytesRefに細心の注意を払ってくださいペイロードを含む:バイト配列が以前に保存したペイロードと同じであると想定できないため、offsetでバイトをチェックする必要があります。インデックスを読み取るときに、LuceneはscorePayloadの呼び出しのためだけに別のバイト配列を割り当てるメモリを浪費しないため、既存のバイト配列への参照を取得します。 Lucene APIに対してコーディングする場合、開発者の利便性よりもパフォーマンスが優先されることに留意する必要があります。

これで、新しいSimilarityができました。実装後、IndexSearcherに設定する必要がありますクエリの実行に使用:

IndexSearcher searcher = new IndexSearcher(... reader for index ...); searcher.setSimilarity(new DialogueAwareSimilarity());

クエリと条件

これでIndexSearcherペイロードをスコアリングできる場合は、ペイロードを認識するクエリを作成する必要もあります。 PayloadTermQuery単一のTermに一致させるために使用できますそれらの一致のペイロードもチェックしながら:

PayloadTermQuery helloQuery = new PayloadTermQuery(new Term('body', 'hello'), new AveragePayloadFunction());

このクエリは用語[hello]に一致します以内 体 フィールド(ここにドキュメントの内容を配置することを思い出してください)。また、すべての用語の一致から最終的なペイロードスコアを計算する関数を提供する必要があるため、すべてのペイロードスコアを平均するAveragePayloadFunctionをプラグインします。たとえば、用語[hello]の場合会話の内側で2回、会話の外側で1回発生すると、最終的なペイロードスコアは²⁄₃になります。この最終的なペイロードスコアは、DefaultSimilarityによって提供されるスコアと乗算されます。ドキュメント全体。

多くの用語がダイアログの外に表示される検索結果を強調せず、ダイアログに用語がまったくないドキュメントのスコアをゼロにしたいため、平均を使用します。

複数のPayloadTermQueryを作成することもできますBooleanQueryを使用するオブジェクトダイアログに含まれる複数の用語を検索する場合(他のクエリタイプは位置を認識しますが、このクエリでは用語の順序は関係ありません):

PayloadTermQuery worldQuery = new PayloadTermQuery(new Term('body', 'world'), new AveragePayloadFunction()); BooleanQuery query = new BooleanQuery(); query.add(helloQuery, Occur.MUST); query.add(worldQuery, Occur.MUST);

このクエリを実行すると、クエリ構造と類似性の実装がどのように連携するかを確認できます。

luceneダイアログ分析パイプライン

クエリの実行と説明

クエリを実行するには、クエリをIndexSearcherに渡します。

TopScoreDocCollector collector = TopScoreDocCollector.create(10); searcher.search(query, new PositiveScoresOnlyCollector(collector)); TopDocs topDocs = collector.topDocs();

Collectorオブジェクトは、一致するドキュメントのコレクションを準備するために使用されます。

コレクターは、ソート、制限、およびフィルタリングの組み合わせを実現するように構成できます。たとえば、会話に少なくとも1つの用語が含まれている上位10のスコアリングドキュメントを取得するには、TopScoreDocCollectorを組み合わせます。およびPositiveScoresOnlyCollector。正のスコアのみを取得すると、ゼロスコアの一致(つまり、ダイアログに用語がないもの)が確実に除外されます。

このクエリの動作を確認するには、クエリを実行してから、IndexSearcher#explainを使用します。個々のドキュメントがどのようにスコアリングされたかを確認するには:

for (ScoreDoc result : topDocs.scoreDocs) { Document doc = searcher.doc(result.doc, Collections.singleton('title')); System.out.println('--- document ' + doc.getField('title').stringValue() + ' ---'); System.out.println(this.searcher.explain(query, result.doc)); }

ここでは、TopDocsのドキュメントIDを繰り返し処理します。検索によって取得されます。 IndexSearcher#docも使用します表示するタイトルフィールドを取得します。 'hello'のクエリの場合、次のようになります。

--- Document whelv10.txt --- 0.072256625 = (MATCH) btq, product of: 0.072256625 = weight(body:hello in 7336) [DialogueAwareSimilarity], result of: 0.072256625 = fieldWeight in 7336, product of: 2.345208 = tf(freq=5.5), with freq of: 5.5 = phraseFreq=5.5 3.1549776 = idf(docFreq=2873, maxDocs=24796) 0.009765625 = fieldNorm(doc=7336) 1.0 = AveragePayloadFunction.docScore() --- Document daved10.txt --- 0.061311778 = (MATCH) btq, product of: 0.061311778 = weight(body:hello in 6873) [DialogueAwareSimilarity], result of: 0.061311778 = fieldWeight in 6873, product of: 3.3166249 = tf(freq=11.0), with freq of: 11.0 = phraseFreq=11.0 3.1549776 = idf(docFreq=2873, maxDocs=24796) 0.005859375 = fieldNorm(doc=6873) 1.0 = AveragePayloadFunction.docScore() ...

出力には専門用語が含まれていますが、カスタムSimilarityがどのように表示されるかを確認できます。実装はスコアリングで使用され、MaxPayloadFunctionはどのように使用されましたか1.0の乗数を生成しましたこれらの試合のために。これは、ペイロードがロードされてスコアリングされ、'Hello'のすべての一致が一致することを意味します。対話の中で起こったので、これらの結果は私たちが期待するところの一番上にあります。

また、ペイロードを含むProject Gutenbergのインデックスのサイズは約4ギガバイトになりますが、私の控えめな開発マシンでは、クエリは即座に発生します。検索の目標を達成するために速度を犠牲にすることはありません。

まとめ

Luceneは、文字の生のストリームを取得してトークンにバンドルし、それらを用語としてインデックスに保持する、強力な専用の全文検索ライブラリです。そのインデックスをすばやくクエリしてランク付けされた結果を提供し、効率を維持しながら拡張の十分な機会を提供します。

Luceneをアプリケーションで直接使用するか、サーバーの一部として使用することで、ギガバイトを超えるコンテンツをリアルタイムで全文検索できます。さらに、カスタム分析とスコアリングにより、ドキュメント内のドメイン固有の機能を利用して、結果またはカスタムクエリの関連性を向上させることができます。

wp-jsonとは

このLuceneチュートリアルの完全なコードリストは次のとおりです。 GitHubで入手可能 。リポジトリには2つのアプリケーションが含まれています:LuceneIndexerAppインデックスを作成するため、およびLuceneQueryAppクエリを実行するため。

入手可能なプロジェクト・グーテンベルクのコーパス BitTorrent経由のディスクイメージとして 、読む価値のある本がたくさん含まれています(Luceneを使用するか、昔ながらの方法で)。

ハッピーインデックス!

設計、封印、提供–ロゴパッケージエクスプレスの力

ツールとチュートリアル

設計、封印、提供–ロゴパッケージエクスプレスの力
TensorFlowにおける最急降下法の多くのアプリケーション

TensorFlowにおける最急降下法の多くのアプリケーション

データサイエンスとデータベース

人気の投稿
ネットプロモータースコアが十分ではありません:ユーザー調査が必要です
ネットプロモータースコアが十分ではありません:ユーザー調査が必要です
シニアクライアントパートナー、ヘルスケア&ライフサイエンス
シニアクライアントパートナー、ヘルスケア&ライフサイエンス
Gulp:サイトの速度を最大化するためのWeb開発者の秘密兵器
Gulp:サイトの速度を最大化するためのWeb開発者の秘密兵器
JSONとXMLの詳細、パート1:各標準の歴史
JSONとXMLの詳細、パート1:各標準の歴史
Aho-Corasickアルゴリズムで文字列検索を征服する
Aho-Corasickアルゴリズムで文字列検索を征服する
 
アプリを収益性の高いものにする、パート2 –モバイルファネルの活用
アプリを収益性の高いものにする、パート2 –モバイルファネルの活用
オープンソースソフトウェア-ビジネスモデルは収益性があるかどうか?
オープンソースソフトウェア-ビジネスモデルは収益性があるかどうか?
製品設計における人間中心の設計の重要性
製品設計における人間中心の設計の重要性
トッププロジェクトマネージャーの5つの不可欠な資質
トッププロジェクトマネージャーの5つの不可欠な資質
ソーシャルネットワークAPI:インターネットの実世界へのポータル
ソーシャルネットワークAPI:インターネットの実世界へのポータル
人気の投稿
  • Webアプリケーションからモバイルアプリケーションへ
  • トップ100シングルファミリーオフィス
  • ミリ秒単位で時間を取得するjavascript
  • ソリューションを使用した資本予算の例
  • 従業員計算機の総コスト
カテゴリー
設計プロセス アジャイル プロセスとツール 収益と成長 革新 製品ライフサイクル トレンド アジャイルタレント リモートの台頭 Webフロントエンド

© 2021 | 全著作権所有

apeescape2.com