我知道工作的例子总是比理论好,但我仍然想先讲一点理论。 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