对于lucene搜索的一些个人笔记

我的笔记:

1.分布搜索(多目录搜索)

我们可以使用 multireader 或 multisearcher 搜索多个索引库。

multireader reader = new multireader(new indexreader[] { indexreader.open(@”c:\index”), indexreader.open(@”\\server\index”) });

indexsearcher searcher = new indexsearcher(reader);

hits hits = searcher.search(query);

indexsearcher searcher1 = new indexsearcher(reader1);

indexsearcher searcher2 = new indexsearcher(reader2);

multisearcher searcher = new multisearcher(new searchable[] { searcher1, searcher2 });

hits hits = searcher.search(query);

还可以使用 parallelmultisearcher 进行多线程并行搜索。


2.多样化的搜索

/** *** 一个关键字,对一个字段进行查询 **** */

QueryParser qp = new QueryParser("content",analyzer);

query = qp.parse(keyword);

Hits hits = searcher.search(query);

 

/** *** 模糊查询 **** */

Term term = new Term("content",keyword);

FuzzyQuery fq = new FuzzyQuery(term);

Hits hits = searcher.search(fq);

 

/** *** 一个关键字,在两个字段中查询 **** */

/*

 * 1.BooleanClause.Occur[]的三种类型: MUST : + and MUST_NOT : - not SHOULD : or

 * 2.下面查询的意思是:content中必须包含该关键字,而title有没有都无所谓

 * 3.下面的这个查询中,Occur[]的长度必须和Fields[]的长度一致。每个限制条件对应一个字段

 */

BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST};

query=MultiFieldQueryParser.parse(keyword,new String[]{"title","content"},flags,analyzer);

 

 

/** *** 两个(多个)关键字对两个(多个)字段进行查询,默认匹配规则 **** */

/*

 * 1.关键字的个数必须和字段的个数相等

 * 2.由于没有指定匹配规定,默认为"SHOULD" 因此,下面查询的意思是:"title"中含有keyword1 或 "content"含有keyword2.

 * 在此例中,把keyword1和keyword2相同

 */

 query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new

 String[]{"title","content"},analyzer);

 

 

/** *** 两个(多个)关键字对两个(多个)字段进行查询,手工指定匹配规则 **** */

/*

 * 1.必须 关键字的个数 == 字段名的个数 == 匹配规则的个数

 * 2.下面查询的意思是:"title"必须不含有keyword1,并且"content"中必须含有keyword2

 */

 BooleanClause.Occur[] flags = new

 BooleanClause.Occur[]{BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.MUST};

 query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new

 String[]{"title","content"},flags,analyzer);

 //设置权重

String[] fields = { "name", "so_province", "so_city","so_level", "so_kind", "so_type"};

Map<String,Float> m = new HashMap<String,Float>(); 

m.put("name", 2.0f);//对“name”的field设置权重

m.put("so_province", 1.0f);

m.put("so_city", 1.0f);

m.put("so_level", 1.0f);

m.put("so_kind", 1.0f);

m.put("so_type", 1.0f);

MultiFieldQueryParser p = new MultiFieldQueryParser(fields,SearchTools.getStandardAnalyzer(), m );

Query mulQ = p.parse("+\""+key+"\"~0 ");

 

/** *** 对日期型字段进行查询 **** */

 

/** *** 对数字范围进行查询 **** */

/*

 * 1.两个条件必须是同一个字段

 * 2.前面一个条件必须比后面一个条件小,否则找不到数据

 *  3.new RangeQuery中的第三个参数,表示是否包含"=" true: >= 或 <= false: > 或 <

 * 4.找出 55>=id>=53 or 60>=id>=57:

 */

Term lowerTerm1 = new Term("id","53");

Term upperTerm1 = new Term("id","55");

RangeQuery rq1 = new RangeQuery(lowerTerm1,upperTerm1,true);

 

Term lowerTerm2 = new Term("id","57");

Term upperTerm2 = new Term("id","60");

RangeQuery rq2 = new RangeQuery(lowerTerm2,upperTerm2,true);

 

BooleanQuery bq = new BooleanQuery();

bq.add(rq1,BooleanClause.Occur.SHOULD);

bq.add(rq2,BooleanClause.Occur.SHOULD);

Hits hits = searcher.search(bq);


3.结果排序 

排序的关键点有两个:

1:首先你要排序的字段必须是被index的,并且是untokenized的。

如:

doc.add(new Field("click", dv.get("click").toString(), Field.Store.NO, Field.Index.UN_TOKENIZED));

2:在检索时候:

如:  

   /*****  排序  *****/

   /*

    * 1.被排序的字段必须被索引过(Indexecd),在索引时不能 用 Field.Index.TOKENIZED

    *   (用UN_TOKENIZED可以正常实现.用NO时查询正常,但排序不能正常设置升降序)

    * 2.SortField类型

    *   SCORE、DOC、AUTO、STRING、INT、FLOAT、CUSTOM 此类型主要是根据字段的类型选择

    * 3.SortField的第三个参数代表是否是降序true:降序  false:升序

    */

   Sort sort = new Sort(new SortField[]{new SortField("click", SortField.INT, true)});

   Hits hits = searcher.search(querystring,sort);

  

    /*

    * 按日期排序

    */

   Sort sort = new Sort(new SortField[]{new SortField("createTime", SortField.INT, false)});

 

    /*****  过滤器 ******/  不建议使用过滤器

   QueryParser qp1 = new QueryParser("content",analyzer);

   Query fquery  = qp1.parse("我");

  

   BooleanQuery bqf = new BooleanQuery();

   bqf.add(fquery,BooleanClause.Occur.SHOULD);

   

   QueryFilter qf = new QueryFilter(bqf);

  

   Hits hits = searcher.search(query);

 

4. doc部分字段的高效查找

我只需要ID字段,但是返回整个Doc,其他两个文本Field也返回了。因为Lucene是倒索引保存信息的,每一个文本Field需要重新组合成原始的字符串,这也是要耗时间的。

searcher的doc函数有一个可以限定只取部分域的:Document doc(int n, FieldSelector fieldSelector)

我下面定义一个FieldSelector,只取某一个给定名字的Field
class SpecialFieldSelector implements FieldSelector {
    protected String m_szFieldName;
    public SpecialFieldSelector( String szFieldName ) {
        m_szFieldName = szFieldName;
    }
   
    public FieldSelectorResult accept(String fieldName) {
        if( fieldName.equalsIgnoreCase(m_szFieldName)) {
            return  FieldSelectorResult.LOAD;
        }
        else {
            return  FieldSelectorResult.NO_LOAD;
        }
    }   
}

再修改我的代码:
ScoreDoc[] scoreDocs = topDoc.scoreDocs;
ArrayList<Document> szTest = new ArrayList<Document>();
FieldSelector fieldSelector = new SpecialFieldSelector(FIELD_ID);
for( int i=0;i<scoreDocs.length;i++) {
        Document doc = searcher.doc(scoreDocs[i].doc, fieldSelector);
        szTest.add(doc);
}

现在返回1.2W个ID耗时0.25秒。虽然比前面只少了大约150毫秒,但是是接近40%的提高了,在负载比较大的应用中还是很重要的。


5.将小索引文件合并到大的索引文件中去(此方法性能不佳)

/** 将小索引文件合并到大的索引文件中去

  *   @param   from   将要合并到to文件的文件

  *   @param   to       将from文件合并到该文件

  *   @param   analyzer  

  */

private   void   mergeIndex(File   from,File   to,Analyzer   analyzer)

{

IndexWriter   indexWriter   =   null;

try{

System.out.println("正在合并索引文件!\t");

indexWriter   =   new   IndexWriter(to,analyzer,   false);

indexWriter.setMergeFactor(100000);

indexWriter.setMaxFieldLength(Integer.MAX_VALUE);

indexWriter.setMaxBufferedDocs(Integer.MAX_VALUE);

indexWriter.setMaxMergeDocs(Integer.MAX_VALUE);

FSDirectory[]   fs   =   {FSDirectory.getDirectory(from,false)};

indexWriter.addIndexes(fs);

indexWriter.optimize();

indexWriter.close();

System.out.println("已完成合并!\t");

}

catch(Exception   e)

{

     Utility.writeLog("合并索引文件出错!mergeIndex()"+e.getMessage(),"");

}

finally

{

try{

if(indexWriter!=null)

indexWriter.close();

}

catch(Exception   e   ){}

}

}

合并时间是从每天的凌晨3点钟开始,一直到早上9点左右,足足用5个小时才合并完成,其中大索引文件大小为4G,小索引为10MB.

 

6、建引时候的优化方案

优化方针:

     1、多线程构建索引

        采用jdk1.5提供的线程池多线程构建索引

     2、构建索引的脚本调优

        采用游标方式抓取数据而不是分页抓取数据

     3、lucene api调优

            indexwriter.setRAMBufferSizeMB(256);// M
            indexwriter.setUseCompoundFile(false);// 多文件索引
            indexwriter.setMergeFactor(10);



你可能感兴趣的:(Lucene,lucene优化,多目录搜索)