Hibernate Search 查询从实际数据库而不是 Elastic DB 索引中获取数据
Hibernate Search query fetching data from Actual database and not from Elastic DB indexes
我们正在尝试在我们的项目中实现弹性搜索。至此我们可以在 ES 下创建索引。但问题是在检索时。当我们触发查询以检索数据时,查询是针对实际数据库触发的,而不是 ES DB 索引。
hibernate.cfg
<property name="hibernate.search.default.indexmanager">elasticsearch</property>
<property name="hibernate.search.default.elasticsearch.host">http://127.0.0.1:9200</property>
<property name="hibernate.search.default.elasticsearch.index_schema_management_strategy">drop-and-create</property>
<property name="hibernate.search.default.elasticsearch.required_index_status">yellow</property>
要搜索的代码:
Session session = HibernateSessionFactory.current().getSession("");
fullTextSession = Search.getFullTextSession(session.getSession());
searchFactory = fullTextSession.getSearchFactory();
QueryBuilder titleQB = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(<MyClassHere>.class).get();
Query query = titleQB.phrase().onField(EMAIL1_EDGE_NGRAM_INDEX).andField(EMAIL1_NGRAM_INDEX)
.boostedTo(5).sentence(searchTerm.toLowerCase()).createQuery();
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query, <MyClassHere>.class);
fullTextQuery.setMaxResults(20);
List<Bascltj001TO> results = fullTextQuery.getResultList();
return results;
实体class:
@Entity
@Indexed
public class MYClass {
private DBAccessStatus dBAccessStatus;
private String optname = "";
private String phone1 = "";
@Fields({
@Field(name = "email1", index = Index.YES, store = Store.YES,
analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
@Field(name = "edgeNGramEmail1", index = Index.YES, store = Store.NO,
analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
@Field(name = "nGramEmail1", index = Index.YES, store = Store.NO,
analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteNGramAnalyzer"))
})
private String email1 = "";
弹性数据库json数据
{
"_index" : "myclass",
"_type" : "myclass",
"_id" : "67",
"_score" : 1.0,
"_source" : {
"id" : "67",
"cltseqnum" : 67,
"email1" : "email@clt.com",
"edgeNGramEmail1" : "email@clt.com",
"nGramEmail1" : "email@clt.com"
}
分析器定义
@AnalyzerDefs({
@AnalyzerDef(name = "autocompleteEdgeAnalyzer",
// Split input into tokens according to tokenizer
tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),
filters = {
// Normalize token text to lowercase, as the user is unlikely to
// care about casing when searching for matches
@TokenFilterDef(factory = PatternReplaceFilterFactory.class, params = {
@Parameter(name = "pattern", value = "([^a-zA-Z0-9\.])"),
@Parameter(name = "replacement", value = " "),
@Parameter(name = "replace", value = "all") }),
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = StopFilterFactory.class),
// Index partial words starting at the front, so we can provide
// Autocomplete functionality
@TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = {
@Parameter(name = "minGramSize", value = "3"),
@Parameter(name = "maxGramSize", value = "50") }) }),
@AnalyzerDef(name = "autocompleteNGramAnalyzer",
// Split input into tokens according to tokenizer
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
// Normalize token text to lowercase, as the user is unlikely to
// care about casing when searching for matches
@TokenFilterDef(factory = WordDelimiterFilterFactory.class),
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = NGramFilterFactory.class, params = {
@Parameter(name = "minGramSize", value = "3"),
@Parameter(name = "maxGramSize", value = "5") }),
@TokenFilterDef(factory = PatternReplaceFilterFactory.class, params = {
@Parameter(name = "pattern", value = "([^a-zA-Z0-9\.])"),
@Parameter(name = "replacement", value = " "),
@Parameter(name = "replace", value = "all") }) }),
您的查询是全文查询,因此它将在 Elasticsearch 集群上执行 - Hibernate Search 无法将其转换为数据库查询。
但是...请记住,您的索引不包含构建实体所需的所有数据。因此,在从 Elasticsearch 集群获取 id 后,Hibernate Search 将在您的数据库上执行查询以获取作为实体的结果。
避免这种情况的唯一方法是使用投影来查询索引的特定字段,但除了非常具体的情况外,获取实体通常是您想要的。
我的猜测是您看到它 运行 是对 both 的查询。它肯定不会 运行 仅在数据库上查询,因为不可能 运行 在数据库上进行这样的全文查询。
默认架构
FullTextQuery 的默认设置是 运行 Elasticsearch 上的查询,以便了解匹配的对象的主键,然后使用此 ID 列表从数据库加载完全托管的域对象。
这通常是人们想要的,因此要确保您获得最新版本的数据并确保对象在事务的安全范围内加载。
它还允许您将更改应用到对象,并在您提交事务时将这些更改应用到您的数据库和 Elasticsearch 集群。
另一个好处是您可以从数据库中加载所有字段,包括未编入索引的字段。因此,您可以跳过所有不需要的字段的索引 运行 查询 - 保持索引轻便快速。
备选方案
如果出于任何原因你只想在 Elasticsearch 上专门执行查询,你只需要使用投影。
参见:
我们正在尝试在我们的项目中实现弹性搜索。至此我们可以在 ES 下创建索引。但问题是在检索时。当我们触发查询以检索数据时,查询是针对实际数据库触发的,而不是 ES DB 索引。
hibernate.cfg
<property name="hibernate.search.default.indexmanager">elasticsearch</property>
<property name="hibernate.search.default.elasticsearch.host">http://127.0.0.1:9200</property>
<property name="hibernate.search.default.elasticsearch.index_schema_management_strategy">drop-and-create</property>
<property name="hibernate.search.default.elasticsearch.required_index_status">yellow</property>
要搜索的代码:
Session session = HibernateSessionFactory.current().getSession("");
fullTextSession = Search.getFullTextSession(session.getSession());
searchFactory = fullTextSession.getSearchFactory();
QueryBuilder titleQB = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(<MyClassHere>.class).get();
Query query = titleQB.phrase().onField(EMAIL1_EDGE_NGRAM_INDEX).andField(EMAIL1_NGRAM_INDEX)
.boostedTo(5).sentence(searchTerm.toLowerCase()).createQuery();
FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query, <MyClassHere>.class);
fullTextQuery.setMaxResults(20);
List<Bascltj001TO> results = fullTextQuery.getResultList();
return results;
实体class:
@Entity
@Indexed
public class MYClass {
private DBAccessStatus dBAccessStatus;
private String optname = "";
private String phone1 = "";
@Fields({
@Field(name = "email1", index = Index.YES, store = Store.YES,
analyze = Analyze.YES, analyzer = @Analyzer(definition = "standardAnalyzer")),
@Field(name = "edgeNGramEmail1", index = Index.YES, store = Store.NO,
analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteEdgeAnalyzer")),
@Field(name = "nGramEmail1", index = Index.YES, store = Store.NO,
analyze = Analyze.YES, analyzer = @Analyzer(definition = "autocompleteNGramAnalyzer"))
})
private String email1 = "";
弹性数据库json数据
{
"_index" : "myclass",
"_type" : "myclass",
"_id" : "67",
"_score" : 1.0,
"_source" : {
"id" : "67",
"cltseqnum" : 67,
"email1" : "email@clt.com",
"edgeNGramEmail1" : "email@clt.com",
"nGramEmail1" : "email@clt.com"
}
分析器定义
@AnalyzerDefs({
@AnalyzerDef(name = "autocompleteEdgeAnalyzer",
// Split input into tokens according to tokenizer
tokenizer = @TokenizerDef(factory = KeywordTokenizerFactory.class),
filters = {
// Normalize token text to lowercase, as the user is unlikely to
// care about casing when searching for matches
@TokenFilterDef(factory = PatternReplaceFilterFactory.class, params = {
@Parameter(name = "pattern", value = "([^a-zA-Z0-9\.])"),
@Parameter(name = "replacement", value = " "),
@Parameter(name = "replace", value = "all") }),
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = StopFilterFactory.class),
// Index partial words starting at the front, so we can provide
// Autocomplete functionality
@TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = {
@Parameter(name = "minGramSize", value = "3"),
@Parameter(name = "maxGramSize", value = "50") }) }),
@AnalyzerDef(name = "autocompleteNGramAnalyzer",
// Split input into tokens according to tokenizer
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
filters = {
// Normalize token text to lowercase, as the user is unlikely to
// care about casing when searching for matches
@TokenFilterDef(factory = WordDelimiterFilterFactory.class),
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
@TokenFilterDef(factory = NGramFilterFactory.class, params = {
@Parameter(name = "minGramSize", value = "3"),
@Parameter(name = "maxGramSize", value = "5") }),
@TokenFilterDef(factory = PatternReplaceFilterFactory.class, params = {
@Parameter(name = "pattern", value = "([^a-zA-Z0-9\.])"),
@Parameter(name = "replacement", value = " "),
@Parameter(name = "replace", value = "all") }) }),
您的查询是全文查询,因此它将在 Elasticsearch 集群上执行 - Hibernate Search 无法将其转换为数据库查询。
但是...请记住,您的索引不包含构建实体所需的所有数据。因此,在从 Elasticsearch 集群获取 id 后,Hibernate Search 将在您的数据库上执行查询以获取作为实体的结果。
避免这种情况的唯一方法是使用投影来查询索引的特定字段,但除了非常具体的情况外,获取实体通常是您想要的。
我的猜测是您看到它 运行 是对 both 的查询。它肯定不会 运行 仅在数据库上查询,因为不可能 运行 在数据库上进行这样的全文查询。
默认架构
FullTextQuery 的默认设置是 运行 Elasticsearch 上的查询,以便了解匹配的对象的主键,然后使用此 ID 列表从数据库加载完全托管的域对象。
这通常是人们想要的,因此要确保您获得最新版本的数据并确保对象在事务的安全范围内加载。
它还允许您将更改应用到对象,并在您提交事务时将这些更改应用到您的数据库和 Elasticsearch 集群。
另一个好处是您可以从数据库中加载所有字段,包括未编入索引的字段。因此,您可以跳过所有不需要的字段的索引 运行 查询 - 保持索引轻便快速。
备选方案
如果出于任何原因你只想在 Elasticsearch 上专门执行查询,你只需要使用投影。
参见: