[英]ElasticSearch query optimization - Java API
我是ES的新手,正在搜索10萬條記錄集。 這是我為數據建立索引的映射和設置JSON:
setings.json
{
"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();
該查詢確實可以幫助我搜索數據並且可以正常工作,但是我的問題是自從使用通配符查詢以來,這花費了很多時間。 有人可以幫助您優化此查詢,還是可以指導我找到最適合我的查詢的查詢? TIA。
首先,讓我首先回答一個簡單的問題:處理大小寫。 如果定義自定義分析器,則可以添加不同的過濾器,這些過濾器將在令牌化程序處理完輸入后應用於每個令牌。
{
"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標記器。 同樣,為了更深入地理解,您可能需要閱讀docs 。 但是提到您的問題時,您的令牌生成器實際上將創建長度為3到10的項。這意味着文本
I am an example TEXT.
基本上會創建很多令牌。 只是顯示一些:
你明白了。 ( 小寫的令牌過濾器現在將小寫這些令牌)
匹配查詢和術語查詢之間的區別:分析匹配查詢,但不分析術語查詢。 實際上,這意味着您的匹配查詢可以匹配多個詞。 例如:您匹配exam"
。
這將匹配實際上3個方面: exa
, xam
和exam
。
這對比賽的分數有影響。 比賽越多,得分越高。 在某些情況下是期望的,在其他情況下則是不希望的。
不分析詞條查詢,這意味着exam
會匹配,但只會匹配一個詞條(當然是exam
)。 但是,由於沒有對其進行分析,因此也沒有將其小寫,這意味着您必須自己編寫代碼。 Exam
永遠不會匹配,因為如果您使用小寫的令牌過濾器,則索引中不會包含大寫字母的詞。
不確定您的用例。 但是我有一種感覺,您可以(甚至想要)確實使用術語查詢。 但是請注意,索引中沒有大小大於10的術語。因為這就是您的ngram-tokenizer所做的。
/編輯:
關於匹配查詢,以及需要使用術語的原因,需要指出一些事情:一些Simple
匹配查詢(例如Simple
也可以匹配example
中的mple
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.