どのようにフィールドをトークン化しますか?それらを完全な文字列として保存しますか?また、どのようにクエリを解析しますか?
さて、私はこれでちょっと遊んでいます。私はla、en、deを削除するためにStopFilterを使用しています。私はその後、 "正確な一致"を行うために複数の組み合わせを取得するためにシングルフィルターを使用しました。たとえば、Bosc de Planavillaは[Bosc] [Bosc Planavilla]としてトークン化され、Bosc de Plana en Blancaは[Bosc] [Bosc Plana] [Plana Blanca] [Bosc Plana Blanca]にトークン化されます。これは、クエリの一部に対して「完全一致」ができるようにするためです。
私は、ユーザーが渡した正確な文字列を照会しますが、そこにもいくつかの適応があります。あなたが探していたものと結果が良く合うように、私は単純なケースに行きました。私は今、人口あたりの仕分けに探しています
public class ShingleFilterTests {
private Analyzer analyzer;
private IndexSearcher searcher;
private IndexReader reader;
public static Analyzer createAnalyzer(final int shingles) {
return new Analyzer() {
@Override
public TokenStream tokenStream(String fieldName, Reader reader) {
TokenStream tokenizer = new WhitespaceTokenizer(reader);
tokenizer = new StopFilter(false, tokenizer, ImmutableSet.of("de", "la", "en"));
if (shingles > 0) {
tokenizer = new ShingleFilter(tokenizer, shingles);
}
return tokenizer;
}
};
}
@Before
public void setUp() throws Exception {
Directory dir = new RAMDirectory();
analyzer = createAnalyzer(3);
IndexWriter writer = new IndexWriter(dir, analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
ImmutableList<String> cities = ImmutableList.of("Bosc de Planavilla", "Planavilla", "Bosc de la Planassa",
"Bosc de Plana en Blanca");
ImmutableList<Integer> populations = ImmutableList.of(5000, 20000, 1000, 100000);
for (int id = 0; id < cities.size(); id++) {
Document doc = new Document();
doc.add(new Field("id", String.valueOf(id), Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.add(new Field("city", cities.get(id), Field.Store.YES, Field.Index.ANALYZED));
doc.add(new Field("population", String.valueOf(populations.get(id)),
Field.Store.YES, Field.Index.NOT_ANALYZED));
writer.addDocument(doc);
}
writer.close();
searcher = new IndexSearcher(dir);
reader = searcher.getIndexReader();
}
@After
public void tearDown() throws Exception {
searcher.close();
}
@Test
public void testShingleFilter() throws Exception {
System.out.println("shingle filter");
QueryParser qp = new QueryParser(Version.LUCENE_30, "city", createAnalyzer(0));
printSearch(qp, "city:\"Bosc de Planavilla\"");
printSearch(qp, "city:Planavilla");
printSearch(qp, "city:Bosc");
}
private void printSearch(QueryParser qp, String query) throws ParseException, IOException {
Query q = qp.parse(query);
System.out.println("query " + q);
TopDocs hits = searcher.search(q, 4);
System.out.println("results " + hits.totalHits);
int i = 1;
for (ScoreDoc dc : hits.scoreDocs) {
Document doc = reader.document(dc.doc);
System.out.println(i++ + ". " + dc + " \"" + doc.get("city") + "\" population: " + doc.get("population"));
}
System.out.println();
}
}
:ここ
は、コード、私が使用しています(Luceneの3.0.3)です。
これはアウト出力します。ここでは
query city:"Bosc Planavilla"
results 1
1. doc=0 score=1.143841 "Bosc de Planavilla" population: 5000
query city:Planavilla
results 2
1. doc=1 score=1.287682 "Planavilla" population: 20000
2. doc=0 score=0.643841 "Bosc de Planavilla" population: 5000
query city:Bosc
results 3
1. doc=0 score=0.5 "Bosc de Planavilla" population: 5000
2. doc=2 score=0.5 "Bosc de la Planassa" population: 1000
3. doc=3 score=0.375 "Bosc de Plana en Blanca" population: 100000
多くの感謝!あなたのアプローチは私が終わったアプローチと似ており、良い結果が得られます。しかし、それは完璧ではありません... 300万のドック指数では、私は応答時間が1秒(1台のマシン上で)になります。さらに、「Indian Bar Paris」を検索するときなどに、「Rich Bar Indian Reserve」を返すなど、奇妙なことがよくあります。可能であれば、スコアリングを使ってもう少し精緻化し、可能であればフィーチャタイプに応じてインデックスブーストを試みます。あなたの親切な助けをありがとう! – azpublic
3百万のドキュメントの1秒間の音があまりにも多く聞こえる。どのようにソートしていますか?プロファイラを使用して、CPUがどこに行くかを調べることができます。私は約70ミリ秒で複雑なクエリとファセットとカスタムソートを持つ4000万のドキュメントインデックスを探しています。 – wesen