我知道工作的例子總是比理論好,但我仍然想先講一點理論。 Elasticsearch的核心是Lucene。所以在將文檔寫入Lucene索引之前,他會經歷分析階段。分析階段可分爲3部分:
- 字符過濾;
- 標記化;
- 令牌過濾
在第一階段中,我們可以扔掉不必要的字符,例如,HTML標籤。有關字符過濾器的更多信息,請參閱official site。 下一階段更有趣。在這裏,我們將輸入文本分割爲記號,稍後將用於搜索。一些非常有用的tokenizers:
- 標準分詞器。它是默認使用的。標記器實現Unicode文本分段算法。在實踐中,您可以使用它將文本分割成單詞並將這些單詞用作記號。
- n-gram標記器。如果你想要搜索單詞的一部分,這就是你需要的。該標記器將文本分割爲n個項目的連續序列。例如,文本「例如」將被分割爲這個標記序列
"fo", "or", "r ", " e", "ex", "for", "or ex"
等.n-gram的長度是可變的,並且可以由min_gram和max_gram params來配置。
- edge n-gram tokenizer。與n-gram標記器相同,除了一件事情 - 該標記器不增加偏移量。例如,文本「例如」將被分割爲這個標記序列
"fo", "for", "for ", "for e", "for ex", "for exa"
等。 關於標記器的更多信息可以在官方網站上找到。不幸的是,由於聲譽低下,我無法發佈更多鏈接。
下一個階段也是該死的有趣。在我們將文本分成標記之後,我們可以用這個做很多有趣的事情。我再次給令牌過濾器的一些非常有用的例子:
- 小寫過濾。在大多數情況下,我們希望得到不區分大小寫的搜索,所以最好將令牌標記爲小寫。
- 詞幹分析過濾器。當我們與自然語言達成協議時,我們遇到很多問題。其中一個問題是一個詞可以有多種形式。 Stemmer過濾器可以幫助我們獲得單詞的根形式。
- 模糊濾波器。另一個問題是用戶經常犯錯。此過濾器添加包含可能的拼寫錯誤的標記。
如果你有興趣看分析的結果,你可以使用這個_termvectors端點
curl [ELASTIC_URL]:9200/[INDEX_NAME]/[TYPE_NAME]/[DOCUMENT_ID]/_termvectors?pretty
現在說說查詢。查詢分爲2個大組。這些組有兩個顯着差異:
- 請求是否會通過分析階段;
- 是否要求有一個確切的答案(是或否)
例子是匹配查詢和搜索項查詢。第一個將通過分析階段,第二個不會。第一個不會給我們一個具體的答案(但給我們一個分數),第二個會。爲文檔創建映射時,我們可以分別指定分析器的索引和搜索分析器的每個字段。
現在有關彈簧數據elasticsearch的信息。這裏講一些具體的例子很有意義。假設我們有一個帶有標題字段的文檔,我們想要搜索該字段的信息。首先,創建一個包含elasticsearch設置的文件。
{
"analysis": {
"analyzer": {
"ngram_analyzer": {
"tokenizer": "ngram_tokenizer",
"filter": [
"lowercase"
]
},
"edge_ngram_analyzer": {
"tokenizer": "edge_ngram_tokenizer",
"filter": [
"lowercase"
]
},
"english_analyzer": {
"tokenizer": "standard",
"filter": [
"lowercase",
"english_stop",
"unique",
"english_possessive_stemmer",
"english_stemmer"
]
"keyword_analyzer": {
"tokenizer": "keyword",
"filter": ["lowercase"]
}
},
"tokenizer": {
"ngram_tokenizer": {
"type": "ngram",
"min_gram": 2,
"max_gram": 20
},
"edge_ngram_tokenizer": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 20
}
},
"filter": {
"english_stop": {
"type": "stop",
"stopwords": "_english_"
},
"english_stemmer": {
"type": "stemmer",
"language": "english"
},
"english_possessive_stemmer": {
"type": "stemmer",
"language": "possessive_english"
}
}
}
您可以將此設置保存到您的資源文件夾中。現在讓我們看看我們的文檔類
@Document(indexName = "document", type = "document")
@Setting(settingPath = "document_index_setting.json")
public class Document {
@Id
private String id;
@MultiField(
mainField = @Field(type = FieldType.String,
index = not_analyzed),
otherFields = {
@InnerField(suffix = "edge_ngram",
type = FieldType.String,
indexAnalyzer = "edge_ngram_analyzer",
searchAnalyzer = "keyword_analyzer"),
@InnerField(suffix = "ngram",
type = FieldType.String,
indexAnalyzer = "ngram_analyzer"),
searchAnalyzer = "keyword_analyzer"),
@InnerField(suffix = "english",
type = FieldType.String,
indexAnalyzer = "english_analyzer")
}
)
private String title;
// getters and setters omitted
}
所以在這裏場冠軍,三個內場:
title.edge_ngram
由邊緣正克用關鍵詞搜索分析搜索。我們需要這個,因爲我們不需要將我們的查詢分割成邊緣n元組;
title.ngram
用於n-grams搜索;
title.english
用於搜索與自然語言的細微差別 和主要字段標題。我們不分析這個,因爲有時候我們想按這個字段排序。 讓我們用簡單的多匹配查詢通過所有這些領域的搜索:
String searchQuery = "blablabla";
MultiMatchQueryBuilder queryBuilder = multiMatchQuery(searchQuery)
.field("title.edge_ngram", 2)
.field("title.ngram")
.field("title.english");
NativeSearchQueryBuilder searchBuilder = new NativeSearchQueryBuilder()
.withIndices("document")
.withTypes("document")
.withQuery(queryBuilder)
.withPageable(new PageRequest(page, pageSize));
elasticsearchTemplate.queryForPage(searchBuilder.build,
Document.class,
new SearchResultMapper() {
//realisation omitted });
搜索是一個非常有趣的和大量的話題。我試圖儘可能簡短地回答,因爲這可能會導致令人困惑的時刻 - 請不要猶豫。
您的映射和集羣設置只能幫助正則表達式 – user3775217
您能否詳細說明您的評論?你的意思是在彈性搜索中配置同義詞嗎? – lives
我不知道,那是在那個時候,你不能再以這樣一種違法的方式再問我,直到我得到我非常體面的要求,或者可能在野外飛行時想到我可能已經學會的東西。謝謝 – user3775217