Lucene-按字段进行搜索,按另一个字段排序,返回到第二个字段

Lucene-按字段进行搜索,按另一个字段排序,返回到第二个字段,lucene,Lucene,我希望开发一个包含以下字段的简单搜索 头衔 总结 人气 如果有人通过说“ga”来搜索,我会搜索部分匹配的标题(例如“游戏”),并根据受欢迎程度对结果进行排序 如果有

我希望开发一个包含以下字段的简单搜索

  • 头衔
  • 总结
  • 人气
如果有人通过说“ga”来搜索,我会搜索部分匹配的标题(例如“游戏”),并根据受欢迎程度对结果进行排序

如果有<10个结果,我想回到总结。但是,我希望摘要匹配比任何标题匹配都要低,再次按受欢迎程度排序

例如,搜索“ga*”

我已经编写了一个简单的实现,它执行1个Lucene搜索,如果有<10个结果,则对大纲进行第二次搜索,然后按语法合并结果。然而,这并不理想,因为我需要解决重复的问题,分页将不能很好地工作——如果可能的话,最好在1中完成这一切

这可能吗?如果可能,如何实现

(我目前正在使用Java Lucene jar开发此功能)

这是我当前的尝试(用Scala编写)

//创建索引
私有def addDoc(w:IndexWriter,clientContent:clientContent,contentType:String):单位={
val单据:单据=新单据()
添加文档(新文本字段(“title”,clientContent.title,Field.Store.YES))
doc.add(新文本字段(“synopsis”,clientContent.synopsis,Field.Store.YES))
添加文档(新的StringField(“id”,clientContent.id,Field.Store.YES))
添加文档(新的IntField(“流行度”,100000-clientContent.popularity.day,Field.Store.YES))
添加文档(新的StringField(“contentType”,contentType,Field.Store.YES))
w、 添加文档(doc);
}
def createIndex:单位={
index=new-RAMDirectory()
val analyzer=新的标准分析仪(版本.LUCENE_43)
val config=new IndexWriterConfig(Version.LUCENE_43,analyzer)
val w=新的索引编写器(索引,配置)
clientApplication.shows.list.map{addDoc(w,,“Show”)}
w、 关闭()
reader=IndexReader.open(索引)
搜索器=新索引搜索器(读卡器)
}
//按一个字段搜索
def dataSearch(queryString:String,section:String,limit:Int):数组[ScoreDoc]={
val collector=TopFieldCollector.create(
新排序(新SortField(“流行”,SortField.Type.INT,true)),
限制、假、真、真、假);
val analyzer=新的标准分析仪(版本.LUCENE_43)
val q=新的QueryParser(Version.LUCENE_43,section,analyzer).parse(queryString+“*”)
searcher.search(q,收集器)
collector.topDocs().scoreDocs
}
//搜索查询
def搜索(查询字符串:字符串)={
println(s“搜索$queryString”)
val titleResults=dataSearch(查询字符串,“标题”,限制)
if(标题结果长度<限制){
val synopsisResults=数据搜索(查询字符串,“大纲”,限制-标题结果长度)
createModel(标题Results++synopsisResults)
}
其他的
createModel(标题结果)
}

您可以先按分数排序,然后按人气排序,从而大大提高标题查询的效率。只要与标题匹配的所有字段的分数相等,且仅与摘要匹配的文档的分数相等,那么这样做就行了:

Sort mySort=new Sort(SortField.FIELD_分数,new SortField(“popularity”,SortField.Type.INT,true));
当然,他们可能不会平等。只要推进足够大,idf不应该成为问题,但是。。。如果不同文档的字段长度不同,除非禁用了规范,否则lengthNorm将使分数不相等。协调因素将导致问题,因为匹配两个字段的文档将比仅匹配标题的文档得分更高。如果一个匹配项在一个字段中出现不止一次,那么tf将明显不同

因此,您需要一种简化评分的方法,并防止所有花哨的lucene相关性评分逻辑妨碍您。你可以通过使用和获得分数来做你想做的事情

querytitlequery=newconstantscorequery(新前缀查询(新术语(“title”,queryString));
titleQuery.setBoost(2);
Query summaryQuery=new ConstantScoreQuery(新前缀Query(新术语(“title”,queryString));
//结合一个demax,这样匹配两个字段就不会得到比标题更高的分数
Query finalQuery=new DisjnctionMaxQuery(0);
添加(标题查询);
添加(summaryQuery);
Sort mySort=新排序(
SortField.FIELD_得分,
新的SortField(“流行”,SortField.Type.INT,true)
);
val collector=TopFieldCollector.create(mySort、limit、false、true、true、false);
searcher.search(finalQuery,collector);
对于您提供的代码,这将起作用,因为除了构造prefixquery之外,您并不真正需要查询解析器。不过,您也可以保留解析器
ConstantScoreQuery
是一个包装查询。您可以同样轻松地包装从
QueryParser.parse返回的查询:

QueryParser parser=新的QueryParser(Version.LUCENE_43,“title”,analyzer);
Query titleQuery=new ConstantScoreQuery(parser.parse(queryString+“*”));
titleQuery.SetBoost(2);
Query summaryQuery=new ConstantScoreQuery(parser.parse(“summary:+queryString+“*”));

那么,让我们看看我们第一次尝试添加了什么-它只是原型代码,所以这可能不是最好的方法感谢您的全面回答!这听起来正是我需要的。
"The Game"      | "About stuff"   | popularity = 3  | (title match)
"Gant charts"   | "great stats"   | popularity = 7  | (title match)
"Some Title"    | "mind the gap"  | popularity = 1  | (summary match)
"Another Title" | "blah games"    | popularity = 5  | (summary match)
// Creating the indexes
private def addDoc(w:IndexWriter , clientContent: ClientContent, contentType:String):Unit ={
  val doc:Document = new Document()
  doc.add(new TextField("title", clientContent.title, Field.Store.YES))
  doc.add(new TextField("synopsis", clientContent.synopsis, Field.Store.YES))
  doc.add(new StringField("id", clientContent.id, Field.Store.YES))
  doc.add(new IntField("popularity", 100000 - clientContent.popularity.day, Field.Store.YES))
  doc.add(new StringField("contentType", contentType, Field.Store.YES))
  w.addDocument(doc);
}

def createIndex: Unit = {
  index = new RAMDirectory()

  val analyzer = new StandardAnalyzer(Version.LUCENE_43)
  val config = new IndexWriterConfig(Version.LUCENE_43, analyzer)
  val w = new IndexWriter(index, config)

  clientApplication.shows.list.map {addDoc(w, _, "Show")}

  w.close()
  reader = IndexReader.open(index)
  searcher = new IndexSearcher(reader)
}


// Searching by one field 
def dataSearch(queryString: String, section:String, limit:Int):Array[ScoreDoc] = {

  val collector = TopFieldCollector.create(
  new Sort(new SortField("popularity", SortField.Type.INT, true)),
    limit,false,true, true, false);       

  val analyzer = new StandardAnalyzer(Version.LUCENE_43)
  val q = new QueryParser(Version.LUCENE_43, section, analyzer).parse(queryString+"*")
  searcher.search(q, collector)
  collector.topDocs().scoreDocs
}

// Searching for a query 
def search(queryString:String) = {
  println(s"search $queryString")

  val titleResults = dataSearch(queryString, "title", limit)

  if (titleResults.length < limit) {
    val synopsisResults = dataSearch(queryString, "synopsis", limit - titleResults.length)  
    createModel(titleResults  ++ synopsisResults)
  }
  else
    createModel(titleResults)
}