如何利用 lucene score机制来实现 关键字 竞价排名

lucene内置的排序方式是按照一定算法的score来排列,document的boost能影响文档的权重,但与关键字并无法实现直接的关系。

比如说对文档一加了100的boost。那么无论搜什么关键字,这个文档都有可能出现在最前面。这个结果并不是我们期望的效果。

有一个办法可以实现按照关键字的排序。

例如:关键字 玻璃

在这个购买了关键字的公司的相关信息document创建lucene索引时。需要人为的添加一个字段.这个数据与用户发付费有关。而与真实信息无关。

Field field=new Field("玻璃","玻璃 玻璃 玻璃")
field name 为什么这样写,在下面搜索的是就知道了。
document.add(field);

根据lucene score 算法。重复2次的score最高。不过这个score的分值与ANALYZER有关系,不同的ANALYZER重复次数不一样。根据lucene score的算法明显和重复次数不是线性的。

这里是一些测试数据

当关键字是n个字长。ANALYZER=WhitespaceAnalyzer
按照score分值,从高到低 关键字的重复频率应该为 2 5 17 8 11 6 16 20 10 15 19 7 18 14 3 9 4 13 12
如果用WhitespaceAnalyzer,这个频率是固定。不管n个字是什么.
都是这样排列。




import java.io.IOException;

import junit.framework.TestCase;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.WhitespaceAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;

import com.linkmd.search.constants.XmlConstants;

/**
 * <b>按照购买的关键字来排序</b>
 * @since 2009-5-7
 * @version 1.0
 */
public class KeywordSearchTest extends TestCase {

	private static final Analyzer ANALYZER = new WhitespaceAnalyzer();
	private static final String[] PAY_KEY ={ "芯片","大脑","大菠萝","家乐福"};
	  private static final int comNumber=20; 
	private static final int[][] result=new int[2][comNumber];
                                        
	/**
	 * @throws Exception
	 */
	@SuppressWarnings( { "static-access", "deprecation" })
	public void testSearch2() throws Exception {
		
		for(int y=0,len=PAY_KEY.length;y<len;y++){
			System.out.println("PAY_KEY.length:"+PAY_KEY[y].length());
		test(y);
		System.out.println();
		}
	}

	private void test(int y) throws CorruptIndexException,
			LockObtainFailedException, IOException, ParseException {
		Directory ram = new RAMDirectory();
		IndexWriter writer = new IndexWriter(ram, ANALYZER, true,
				MaxFieldLength.UNLIMITED);

		for (int i = 0; i <comNumber; i++) {
			Document doc = new Document();
			Field field = new Field("companyName", "公司" + i,
					Field.Store.YES, Field.Index.NOT_ANALYZED);
			doc.add(field);

			/**
			 * 付费字段 关键字设置
			 */
			StringBuilder key = new StringBuilder();
			String finalKey = "";
			if (i % 1 == 0) {
				for (int x = 0; x < i; x++) {
					key.append(this.PAY_KEY[y]);
					key.append(" ");
				}
				finalKey = key.toString();
			}
			Field payField = new Field("pay_key_word", finalKey,
					Field.Store.YES, Field.Index.ANALYZED);
			doc.add(payField);
			writer.addDocument(doc);
			// System.out.println(doc);
		}
		writer.close();

		IndexSearcher searcher = new IndexSearcher(ram);
		QueryParser p = new QueryParser("pay_key_word", ANALYZER);
		Query q = p.parse(this.PAY_KEY[y]);
		Hits hits = searcher.search(q);
		System.out.println("total:"+hits.length());
		for (int i = 0, size = hits.length(); i < size; i++) {
			Document doc = hits.doc(i);
			int length = doc.getField("pay_key_word").toString().split(" ").length;
			System.out.print(length+" ");
		}
		searcher.close();
	}

	 
}





现在索引已经建好了。搜索的时候。如果某一个用户输入了玻璃。应该先去数据库查一下,是否这个关键字已经被购买。如果购买了,那么在查询的时刻,我们需要在query的构造上加入
"玻璃":"玻璃"。然后sort数组加上 "玻璃",然后是普通的字段,比如 info 字段的 玻璃 这样查询的顺序就应该按照我们的意思来排序了。

我需要先试试效果。应该可行。

不过其实要实现 关键字 还有很多办法。当然直接结合数据库也可以实现。


社区购物 彤瑶诗佳西兴店正品名牌全场四折

猜你喜欢

转载自wutaoo.iteye.com/blog/381874