ElasticSearch查询优化-Java API
我是ES的新手,正在搜索100k数据的记录集。 这是我的映射和设置JSON,我用它为数据编制了索引: setings.jsonElasticSearch查询优化-Java API,java,
elasticsearch,query-optimization,wildcard,Java,
elasticsearch,Query Optimization,Wildcard,我是ES的新手,正在搜索100k数据的记录集。 这是我的映射和设置JSON,我用它为数据编制了索引: setings.json { "index": { "analysis": { "tokenizer": { "ngram_tokenizer": { "type": "ngram", "min_gram": 3,
{
"index": {
"analysis": {
"tokenizer": {
"ngram_tokenizer": {
"type": "ngram",
"min_gram": 3,
"max_gram": 10
}
},
"analyzer": {
"ngram_tokenizer_analyzer": {
"type": "custom",
"tokenizer": "ngram_tokenizer"
}
}
}
}
}
mappings.json
{
"product": {
"properties": {
"name": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"description": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"vendorModelNumber": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"brand": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"specifications": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"upc": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"storeSkuId": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
},
"modelNumber": {
"type": "string",
"analyzer": "ngram_tokenizer_analyzer",
"store": true
}
}
}
}
我需要根据所提到的所有字段按一定的优先级查询文档。这是我搜索所有记录的查询
BoolQueryBuilder query = QueryBuilders.boolQuery();
int boost = 7;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("name", "*" + str.toLowerCase() + "*").boost(boost));
}
boost--;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("description", "*" + str.toLowerCase() + "*").boost(boost));
}
boost--;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("modelNumber", "*" + str.toLowerCase() + "*").boost(boost));
}
boost--;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("vendorModelNumber", "*" + str.toLowerCase() + "*").boost(boost));
}
boost--;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("storeSkuId", "*" + str.toLowerCase() + "*").boost(boost));
}
boost--;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("upc", "*" + str.toLowerCase() + "*").boost(boost));
}
boost--;
for (String str : dataSplit) {
query.should(QueryBuilders.wildcardQuery("brand", "*" + str.toLowerCase() + "*").boost(boost));
}
client.prepareSearch(index).setQuery(query).setSize(200).setExplain(true).execute().actionGet();
这个查询确实可以帮助我搜索数据,而且效果很好,但我的问题是,因为我使用通配符查询,所以需要花费很多时间。
请有人帮我优化这个查询,或者指导我找到最适合我搜索的查询?
蒂亚 首先,让我先回答一个简单的问题:处理区分大小写。如果定义自定义分析器,则可以添加不同的过滤器,这些过滤器在标记器处理输入后应用于每个标记
{
"index": {
"analysis": {
"tokenizer": {
"ngram_tokenizer": {
"type": "ngram",
"min_gram": 3,
"max_gram": 10
}
},
"analyzer": {
"ngram_tokenizer_analyzer": {
"type": "custom",
"tokenizer": "ngram_tokenizer",
"filter": [
"lowercase",
...
]
}
}
}
}
如您所见,存在一个现有的小写过滤器,它将简单地将所有标记转换为小写。我强烈建议您参考。有很多这样的令牌过滤器
现在是更复杂的部分:NGram标记器。同样,为了更深入地理解,您可能需要阅读。但提到您的问题,您的标记器基本上会创建长度为3到10的术语。这意味着文本
I am an example TEXT.
基本上会创建很多代币。仅举几个例子:
尺码3:I a、am、am、…、TEX、EXT
尺寸4:我是,我是,我是,…,特克斯,文本。
尺码10:我是前任。。。
你明白了。小写标记过滤器现在将这些标记小写
匹配和术语查询之间的区别:将分析匹配查询,而不分析术语查询。事实上,这意味着您的匹配查询可以匹配多个术语。例:你和考试成绩相符
事实上,这将匹配3个术语:exa、xam和exam
这对比赛的分数有影响。比赛越多,分数越高。在某些情况下,这是需要的,在其他情况下不是
不会分析学期查询,这意味着考试将匹配,但当然只有一个学期考试。然而,由于它没有被分析,它也不是小写的,这意味着你必须自己在代码中这样做。考试永远不会匹配,因为如果使用小写标记过滤器,索引中没有带大写字母的术语
不确定您的用例。但我有一种感觉,你可以甚至想要使用查询这个词。但请注意,索引中没有大于10的项。因为你的ngram标记器就是这么做的
/编辑:
关于匹配查询,以及您可能希望使用术语的原因,值得指出的是:一些匹配查询(如Simple)也将匹配示例中的mple。为什么首先使用通配符查询?使用具有3+的ngram标记器,正常匹配查询应使用长度超过2个字符的输入。或者ngram标记器的原因是什么?旁注;使用定义的此分析器,您的查询将区分大小写。可能是有意的,但很不寻常。谢谢@Slomo你是对的。我不应该在ngram中使用通配符。我可以不区分大小写吗?对于ngram,我应该使用术语查询或匹配进行查询,哪种方式更为理想?如果这不是一个合理的问题,那么很抱歉:详细解释请参见tnx a lot@Slomo。将对我的代码进行优化,并对文档进行检查:因此,假设我需要在多个字段上搜索多个值,使用匹配查询的bool将是一个不错的选择,对吗?@DivyaMenon您可以。或者,您也可以使用where,您还应该能够对字段进行加权。也许一个具有预期结果的具体查询示例有助于回答您的问题。