这篇文章是我对自己在自学探索 Elasticsearch 全文搜索功能时学到的概念的一个总结(如果是大佬,请手下留情),大概算是 A Quick Glimpse Into Elasticsearch (Full-Text Search Part),并不一定能帮助读者建构起对于 Elasticsearch 本身客观成体系的认识。(实际上如果只是为了使用 Elasticsearch,也并不需要完全了解其工作机制。)如有需要可参考文末的官方文档和参考资料。
速度更快——在 full-text search 领域性能更佳,数据量越大时会越明显。
效果更好——搜索条件可以非常灵活,分布式设计易于扩展。
(当然 Elasticsearch 还有分析、聚合等其他功能,而 MySQL 等关系型数据库也有其更广泛丰富的需求,两者的定位并不相同。一般推荐将常规数据库作为业务数据的主要存储处,向 Elasticsearch 导入其中的部分数据进行索引以方便搜索。)
https://www.elastic.co/cn/downloads/elasticsearch 有详细的逐步介绍。
没有什么特殊的依赖、配置等,只需要下载解压运行,或者 yum / apt / homebrew,抑或 docker。
安装完成后,Elasticsearch Server 默认运行于本机 9200 端口,提供 REST API——这意味着现在可以通过普通的浏览器来尝试访问。http://localhost:9200/ (另有 9300 端口供 TCP 协议客户端使用和节点间通信)
可以通过 bulk 来批量导入 JSON 形式的数据,或者使用 Logstash 等从已有数据库中导入。
Document 文档:序列化为 JSON 格式存储、可被索引的一个数据单元,被指定了唯一 ID。一篇文档可包含多个字段。
Field 字段:键-值对,字段可被定义为某一类型,如 text (适用于全文搜索),keyword (适用于仅会用于精确搜索的用途,如"status": "published"),integer,date,boolean,nested 等。
Index 索引:所谓的“全文搜索”不是真的在每次搜索时读取一遍全部文本,而是先建立索引,需要搜索时再查询索引。这里指的是 inverted index,而 Elasticsearch index 作为名词是另一个概念,见下文。
Mapping 映射:文档结构,类似于 MySQL 的 Schema,在创建 index 时指定(之后可修改),定义了文档包含字段的名称及类型。Elasticsearch 也可以在不定义 mapping 的情况下使用( schema-less ),此时它会通过第一个存入的数据推断字段类型。GET /<index>/_mapping 可以查看当前<index>的 mapping。</index></index>
Analyzer 分词器:索引时首先要分词才能建立索引。搜索时也是如此,若搜索的不止一个词,而是包含多个词的短语或句子,则先用分词器分离,再进行搜索。英文的分词显然较为容易,中文分词推荐 ik_max_word (最细粒度拆分出尽可能多的词语组合,官方说“适合 Term Query”)和 ik_smart (最粗粒度的拆分,“适合 Phrase 查询”)。搜索和索引的分词器可以不同,若在搜索时未指定分词器,则默认为索引的默认分词器。
Cluster 集群,Node 节点,Index (Indices) 索引, Shard 切片, Replica 副本切片:Elasticsearch 是分布式设计,一个对外提供服务的 Elasticsearch Server 即是一个 Cluster 集群,可以添加 Node 节点以提升性能、容量与冗余,存入的数据与收到的查询请求将被自动分配。(在同一台机器上运行多个 Node 也是可行的。)一个 Elasticsearch index 是文档的集合,这些文档一般具有相似特征。在增删改查这批文档时需要指定 index 的名字。Indices 是 index 的复数形式。一个 Elasticsearch Index 包含一个或多个 Shard 切片,一个切片实际上是一个 Lucene Index 实例( Apache Lucene 是 Elasticsearch 的底层基础),可以说 Shard 是数据的容器,但与使用 ES 服务的应用程序直接交互的是 Index。Shard 分为 primary shard 主切片和 replica shard 副本切片,文档存储于主切片中,而副本切片是主切片的一份拷贝,提供冗余并处理请求。
Near Real-Time 准实时:在数据存入后,它就在 1 秒内被索引而可查询。
Query DSL 查询专用语言:一套描述搜索条件的语言,格式为 JSON。
Score:搜索结果中的某篇文档与搜索要求的契合程度。一般情况下是相关度,目前 Elasticsearch 默认采用 BM25 算法,过去曾使用过 TF/IDF (词频 /逆向文档频率)。也可以在搜索请求中指定,当满足某条件时增加或减少评分,或直接给出固定分值。
建议使用 curl 命令来测试下面的查询。官方给出的示例:
curl -XGET 'http://localhost:9200/twitter/_search?pretty=true' -H 'Content-Type: application/json' -d '
{
"query" : {
"match" : { "user": "kimchy" }
}
}'
如果要用浏览器 URI 进行简单搜索则需要用到 Lucene 查询语法(参考: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html 和 https://lucene.apache.org/core/2_9_4/queryparsersyntax.html ),给个例子(注意 AND ): http://localhost:9200/post_index/_search?q=user:CoolSpring%20AND%20content:Surface&size=30&pretty。
match: 最常用的查询方式。若输入的是短语或句子,则 Elasticsearch 会先用分词器分开,再进行搜索。只关心这些词是否都出现,而不考虑它们之间的距离。
{
"query": {
"match": {
"content": "quick fox"
}
}
}
match_phrase: 短语匹配。将查询内容分词成为词的列表后,搜索时考虑它们在文本中的相对位置。可以指定一个 slop 值,即允许的最大距离。slop 默认为 0,此时可以看作“完全匹配”(均出现,且相邻)。
{
"query": {
"match_phrase": {
"content": "包含一字不差的内容才显示为结果"
}
}
}
term: 精确匹配。比较适合用在 keyword 类型的字段,或者 board_id, topic_id, user_id 这种精确值字段( exact value string field )。
{
"query": {
"term": {
"user": {
"value": "Kimchy",
"boost": 1.0
}
}
}
}
bool: 用以连接多个布尔查询( must, must_not, should, filter )
must: 如其名,必须出现。
must_not: 不能出现。
should: “应该”出现。
filter: 必须出现。与 must 不同的是查询的评分将被忽略。
包含多个词的 match 查询经过分词后可以改写,前述第一个 match 查询示例在内部等效于
{
"query": {
"bool": {
"should": [
{"term": { "text": "quick" }},
{"term": { "text": "fox" }}
]
}
}
}
minimum_should_match: 至少有几个 /百分之几的 should 语句匹配才可出现在结果中。
_source: 在索引时传递的原始 JSON 文档数据。索引与原内容并不相同,_source 本身不被索引、不可搜索,只是保存。
from, size: 易于理解,用于分页搜索中。
rescore: 对于 query 返回的前 n 个搜索结果(如 100-500 个)按照已有分数和新的条件进行重新评分排列。“match 返回的搜索结果不考虑词的距离所以效果不好”的问题可能很常见,一种方法时可以用简单的 bool{must: match, should: match_phrase}“使用邻近度提高相关度”的方式来解决:
{
"query": {
"bool": {
"must": {
"match": {
"message": {
"query":"the quick brown",
"minimum_should_match": "30%"
}
}
},
"should": {
"match_phrase": {
"message": {
"query": "the quick brown",
"slop": 2
}
}
}
}
}
}
但是由于 match_phrase 比较消耗性能(相对于普通的 match 而言),并且用户一般只关心结果前几页,所以可以选择用 rescore 仅对前 50 项进行处理。
{
"query" : {
"match" : {
"message" : {
"operator" : "or",
"query" : "the quick brown"
}
}
},
"rescore" : {
"window_size" : 50,
"query" : {
"rescore_query" : {
"match_phrase" : {
"message" : {
"query" : "the quick brown",
"slop" : 2
}
}
},
"query_weight" : 0.7,
"rescore_query_weight" : 1.2
}
}
}
Elasticsearch 的使用实在很难穷尽,笔者在自学过程中还只能管窥一二,许多功能还没来得及探索。在写这篇文章的时候,关于导入文档的具体操作等重要内容也没有提及。不过有句话说得好,文档和代码是最好的学习资源。Elasticsearch 基于 Apache Lucene,分为 Apache 2.0 授权下的开源版、Elastic License 下的免费版,和商业版。(不过就普通使用的小规模搜索用途而言不大需要研究它的代码。)官方英文文档见: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html。
引用了来自官方文档的一些例子;
What is ElasticSearch? Why ElasticSearch? Advantages of ElasticSearch!: https://medium.com/@AIMDekTech/what-is-elasticsearch-why-elasticsearch-advantages-of-elasticsearch-47b81b549f4d (写了一半查资料时看到这篇文章,深受启发。一部分内容参考了它,在此感谢并推荐。)
1
hugee 2020-03-14 20:28:21 +08:00
感觉好重啊
|
2
Heartbleed 2020-03-14 20:32:36 +08:00 via Android
这个是不是没有 Python 版本的..
|
3
hantsy 2020-03-14 20:59:58 +08:00
@Heartbleed 服务器端跟你没关系的。一般使用都是客户端,各种语言的 Client 应该都有。
|
4
CoolSpring OP @Heartbleed
关于客户端官方提供了两个 Python 库:更灵活自由的 low-level 的[elasticsearch-py]( https://github.com/elastic/elasticsearch-py)和更 Pythonic 的 high-level 的[elasticsearch-dsl-py]( https://github.com/elastic/elasticsearch-dsl-py) |
5
L00kback 2020-03-14 23:03:16 +08:00 via Android
顶一顶,在数据分析领域是一个很实用的工具。配合 kibana 做可视化太舒服了,非常快速,功能强大。
|
6
est 2020-03-15 01:22:24 +08:00
把 ES 调教好不容易。比如默认 shard 几个好?
|
7
SpencerCJH 2020-03-15 02:43:31 +08:00
我最近在集成阿里云的 open search,目的就是降低这一块的学习门槛...
|
8
yepinf 2020-03-15 10:01:58 +08:00
ES 好像也是吃内存大户
团队最后用了 solr |
9
ddup 2020-03-15 10:14:43 +08:00
ES 用起来还是挺简单的,吃透还是要下一番功夫的。
|