这是我第一次处理优化的搜索功能,而我的部分熟练程度是在android开发的前端,但是我愿意冒险进行休眠搜索。我确实了解SQL“ LIKE”查询的功能,它的功能及其局限性,这就是我直接进入休眠搜索(lucene)的原因,我的目标是根据输入(输入查询)提供自动建议。这就是我到目前为止所得到的
@Indexed
@Table (name = "shop_table")
@Entity
@AnalyzerDef(name = "myanalyzer",
tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class), //
filters = { //
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = WordDelimiterFilterFactory.class),
@TokenFilterDef(factory = EdgeNGramFilterFactory.class, params =
{ @Parameter(name = "maxGramSize", value = "1024") }),})
@Analyzer(definition = "myanalyzer")
public class Shop implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
enter code here
@Field(index = Index.YES, store = Store.YES, analyze = Analyze.YES)
@Column(name = "name")
private String name;
... other methods
我的查询
Query lucenQuery = qb.keyword().onField("name").matching(searchTerm).createQuery();
这只是一个基本查询,我只专注于分析器配置以获取所需的内容,这确实令人困惑,我应该专注于哪一部分才能实现所需的标记化?过滤?还是查询本身? 无论如何,我已经索引了这两个词组。
"Apache Lychee Department"
"Apache Strawberry Club Large"
当我处理/查询“ Straw”时,它会给我 Apache Strawberry Club Large 但是当我处理/查询“ Lychee ”或“ Apache Lychee ”时,查询给了我两个?我只期望 Apache Lychee Department
我了解我所有配置的方式是
EdgeNGramFilterFactory (1024)将为我提供一系列1,024个EdgeNGrams索引
LowerCaseFilterFactory 将给我所有小写的索引
WordDelimiterFilterFactory 通过将查询作为一个单词对其进行过滤,并提供匹配的数据。
,每个条目/数据将由 KeywordTokenizerFactory 标记为关键字,并由EdgeNGram索引1,024
我试图查询一个短语,但仍然得到相同的输出
Query luceneQuery = qb.phrase().onField("name").sentence(searchTerm).createQuery();
我的目标是进行自动建议。或者至少从模仿sql的“ LIKE”开始。
答案 0 :(得分:0)
您应该考虑两件事:
这尤其意味着您的查询“ Lychee”将被分析为“ L Ly Lyc Lych Lyche Lychee”之类的东西(由于使用了边缘ngram过滤器)。之前已对字符串“ Apache Strawberry Club Large”进行了分析,由于使用了边缘ngram过滤器,因此将“ Large”一词扩展为“ L La Lar Larg Large”。因此,查询“ Lychee”将与“ Apache Strawberry Club Large”匹配,仅仅是因为它们都包含一个以L ...开头的单词。
这显然是不受欢迎的行为。
第一步是更改查询分析的方式,以免最终匹配完全不相关的文档。 基本上,您将需要定义另一个几乎相同的分析器,但没有“ edge ngram”过滤器。然后,您需要告诉Hibernate Search使用该分析器来分析您的查询。
有关详细说明,请参见this answer。
第二步,如果文档中存在 all 个条款,则需要使查询匹配。为此,最简单的解决方案是使用simple query string query代替关键字查询。
替换此:
Query lucenQuery = qb.keyword().onField("name").matching(searchTerm).createQuery();
与此:
Query lucenQuery = qb.simpleQueryString().onField("name").withAndAsDefaultOperator().matching(searchTerm).createQuery();
键是对.withAndAsDefaultOperator()
的呼叫。
此更改将产生其他一些效果,例如在输入字符串中启用特殊语法,因此,我建议您阅读参考文档以了解simpleQueryString
的确切含义。
答案 1 :(得分:0)
通过@yrodiere,我做到了这一点
@Indexed
@Table (name = "shop_table")
@Entity
@AnalyzerDef(name = "edgeNgram",
tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = EdgeNGramFilterFactory.class, params =
{ @Parameter(name = "maxGramSize", value = "1024") }),
})
@AnalyzerDef(name = "search_query_analyzer",
tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
filters = {
@TokenFilterDef(factory = ASCIIFoldingFilterFactory.class),
@TokenFilterDef(factory = LowerCaseFilterFactory.class)
})
public class Shop implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Field(store = Store.YES, analyze = Analyze.YES)
@Column(name = "name")
@Analyzer(definition = "edgeNgram")
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
和我的查询
QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Shop.class)
.overridesForField("name", "search_query_analyzer").get();
Query lucenQuery = qb.simpleQueryString().onField("name").withAndAsDefaultOperator().matching(shopSearchTerm).createQuery();
但是我不确定我是否以正确的方法实施它。.