Elasticsearch 使用
1. 搜索使用
1.1 搜索请求的结构体
现在我们已经看到了一些基本知识,让我们尝试一下更加真实的数据集(结构化数据)。我准备了关于金庸先生的小
说的 JSON 文档样本。每个文档都有以下模式:
// 样本一
{
"title": "射雕英雄传",
"people": ["郭靖", "黄蓉", "杨康", "穆念慈"],
"year": 1962,
"text": "该小说历史背景突出,场景纷繁,气势宏伟,具有鲜明的“英雄史诗”风格;在人物创造与情节安排上,它
打破了传统武侠小说一味传奇,将人物作为情节附庸的模式,坚持以创造个性化的人物形象为中心,坚持人物统帅故事,按
照人物性格的发展需要及其内在可能性、必然性来设置情节,从而使这部小说达到了事虽奇人却真的妙境。",
"kongfu": ["蛤蟆功", "黯然销魂掌", "降龙十八掌", "双手互搏术"]
}
//样本二
{
"title": "天龙八部",
"people": ["段誉", "萧峰", "虚竹", "丁春秋"],
"year": 1962,
"text": "这部小说以宋哲宗时代为背景,通过宋、辽、大理、西夏、吐蕃等王国之间的武林恩怨和民族矛盾,从哲学
的高度对人生和社会进行审视和描写,展示了一幅波澜壮阔的生活画卷。其故事之离奇曲折、涉及人物之众多、历史背景之
广泛、武侠战役之庞大、想象力之丰富当属“金书”之最。作品风格宏伟悲壮,是一部写尽人性、悲剧色彩浓厚的史诗巨
著。",
"kongfu": ["六脉神剑", "千蛛万毒手", "九阴白骨爪", "化骨绵掌"]
}
//样本三
{
"title": "笑傲江湖",
"people": ["令狐冲", "任盈盈", "岳灵珊", "林平之"],
"year": 1960,
"text": "福建林远图以七十二路辟邪剑法称雄武林,创立福威镖局,驰骋江湖。远图死后,子孙无能,四方豪杰纷纷
觊觎辟邪剑谱。福威镖局总镖头林震南一门被青城派屠戮殆尽。遗孤林平之拜投华山派掌门君子剑岳不群门下,一心学艺报
仇。",
"kongfu": ["独孤九剑", "辟邪剑法", "葵花宝典", "七伤拳"]
}
//样本四
{
"title": "倚天屠龙记",
"people": ["张无忌", "赵敏", "张翠山", "殷素素"],
"year": 1961,1.2创建索引
在ElasticSearch索引中,对应于CRUD中的“创建”和“更新” - 如果对具有给定类型的文档进行索引,并且要插入原先不
存在的ID。 如果具有相同类型和ID的文档已存在,则会被覆盖。
要索引第一个JSON对象,我们对REST API创建一个PUT请求到一个由索引名称,类型名称和ID组成的URL。
"text": "少林寺觉远禅师看护《楞伽经》不力,导致经书被尹克西和潇湘子盗走。潇湘子和尹克西互相猜忌残杀,临
终之前幡然醒悟,委托何足道向觉远转达经书的下落。何足道接受委托,并向少林寺发出挑战。适逢郭靖、黄蓉的女儿郭襄
前往少林寺寻找杨过,从罗汉掌首座无色禅师处得知何足道挑战少林武功的消息,遂在约定日子只身前往观战。觉远禅师的
弟子张君宝在与何足道一战之中暴露了偷学武功的事实,犯了寺规,受到少林寺众僧的围攻。于是觉远携张君宝、郭襄突出
重围,却在途中圆寂。张君宝与郭襄分手之后,只身前往武当山修学觉远生前传授的九阳真经,并深得道家冲虚圆通之功的
精髓,加以融会贯通,创出了武当一派武功,遂自号三丰。",
"kongfu": ["太极剑", "吸星大法", "七伤拳", "玄冥神掌"]
}
http : //localhost:9200/books/jinyong/1 // 创建 movies 下金庸先生的作品
curl - XPUT "http://localhost:9200/books/jinyong/1" // 创建 << 射雕英雄传 >> 作品为索引
curl - XPUT "http://localhost:9200/books/jinyong/2" // 创建 << 天龙八部 >> 作品为索引
curl - XPUT "http://localhost:9200/books/jinyong/3" // 创建 << 笑傲江湖 >> 作品为索引
curl - XPUT "http://localhost:9200/books/jinyong/4" // 创建 << 倚天屠龙记 >> 作品为索引
// 执行结果分别为:
{
"_index": "books",
"_type": "jinyong",
"_id": "1",//文档ID
"_version": 1,//版本号(_version)可用于跟踪文档已编入索引的次数
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
//... 字段
注释
_
1.3 文本的搜索
1.3.1 搜索所有索引和所有类型
在实际场景中大家一定会遇到对文本中的单词进行搜索如:在一本书中找某一个人物,在日志文件中找对应的关键字
等等,那么下面解释下 es 在这些文章中的搜索的应用
如何使用 http://localhost:9200/_search - 搜索所有索引和所有类型。
// 这边以全文搜索小说为例创建请求参数
{
"query": {
"query_string": {
"query": "小说"
}
}
}
响应结果:
{
"took": 18,
"timed_out": false,
"_shards": {
"total": 7,
"successful": 7,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 2.2695534,
"hits": [{
"_index": "books",
"_type": "jinyong",
"_id": "1",
"_score": 2.2695534,
"_source": {
"title": "射雕英雄传",
"people": [
"郭靖",
"黄蓉",
"杨康",
"穆念慈"
],
"year": 1962,
"text": "该小说历史背景突出,场景纷繁,气势宏伟,具有鲜明的“英雄史诗”风格;在人物创
造与情节安排上,它打破了传统武侠小说一味传奇,将人物作为情节附庸的模式,坚持以创造个性化的人物形象为中心,坚
持人物统帅故事,按照人物性格的发展需要及其内在可能性、必然性来设置情节,从而使这部小说达到了事虽奇人却真的妙
境。",
"kongfu": [
"蛤蟆功",
"黯然销魂掌",
"降龙十八掌",
"双手互搏术"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "2",
"_score": 1.4682897,
"_source": {
"title": "天龙八部",
"people": [
"段誉",
"萧峰",
"虚竹",
"丁春秋"
],
"year": 1962,
"text": "这部小说以宋哲宗时代为背景,通过宋、辽、大理、西夏、吐蕃等王国之间的武林恩
怨和民族矛盾,从哲学的高度对人生和社会进行审视和描写,展示了一幅波澜壮阔的生活画卷。其故事之离奇曲折、涉及人
物之众多、历史背景之广泛、武侠战役之庞大、想象力之丰富当属“金书”之最。作品风格宏伟悲壮,是一部写尽人性、悲剧
色彩浓厚的史诗巨著。",
"kongfu": [
"六脉神剑",
"千蛛万毒手",
"九阴白骨爪",
"化骨绵掌"
]
}
}
1.3.2 指定搜索的字段
如何使用 http://localhost:9200/_search - 搜索所有索引和所有类型。
}
}
// 这边以全文搜索小说为例创建请求参数
{
"query": {
"query_string": {
"query": "射雕英雄传",
"fields": ["title"]
}
}
}
//响应结果:
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 5.758131,
"hits": [
1.3.3 过滤与近似匹配
因为在索引中有四部小说在 kongfu 字段 ( 从类别字段 ) 中包含 “ 七伤拳 ” ,所以得到了上述查询的 2 个命中。 现在,想
象一下,如果我们想限制不是 1961 年发布的电影。要做到这点,需要应用一个过滤器,要求 “ year ” 字段不等于 1961 。
{
"_index": "books",
"_type": "jinyong",
"_id": "1",
"_score": 5.758131,
"_source": {
"title": "射雕英雄传",
"people": [
"郭靖",
"黄蓉",
"杨康",
"穆念慈"
],
"year": 1962,
"text": "该小说历史背景突出,场景纷繁,气势宏伟,具有鲜明的“英雄史诗”风格;在人物创
造与情节安排上,它打破了传统武侠小说一味传奇,将人物作为情节附庸的模式,坚持以创造个性化的人物形象为中心,坚
持人物统帅故事,按照人物性格的发展需要及其内在可能性、必然性来设置情节,从而使这部小说达到了事虽奇人却真的妙
境。",
"kongfu": [
"蛤蟆功",
"黯然销魂掌",
"降龙十八掌",
"双手互搏术"
]
}
}
]
}
}
{
"query": {
"bool": {
"must": [
{ "match": { "kongfu": "七伤拳" } }
],
"must_not": [
{ "match": { "year": 1961 } }
]
}}
}
//响应结果
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 8,
"successful": 8,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 2.1470044,
"hits": [
{
"_index": "books",
"_type": "jinyong",
"_id": "3",
"_score": 2.1470044,
"_source": {
"title": "笑傲江湖",
"people": [
"令狐冲",
"任盈盈",
"岳灵珊",
"林平之"
],
"year": 1960,
"text": "福建林远图以七十二路辟邪剑法称雄武林,创立福威镖局,驰骋江湖。远图死后,子
孙无能,四方豪杰纷纷觊觎辟邪剑谱。福威镖局总镖头林震南一门被青城派屠戮殆尽。遗孤林平之拜投华山派掌门君子剑岳
不群门下,一心学艺报仇。",
"kongfu": [
"独孤九剑",
"辟邪剑法",
"葵花宝典",
"七伤拳"
]
}
}
]
}
}
布尔查询中每个 must , should,must_not 都被称为查询子句。每个 must 或者 should 查询子句中的条件都会影响
文档的相关得分。得分越高,文档跟搜索条件匹配得越好。默认情况下, Elasticsearch 返回的文档会根据相关性算
分倒序排列。
must_not 子句中认为是过滤条件。它会过滤返回结果,但不会影响文档的相关性算分,你还可以明确指定任意过滤
条件去筛选结构化数据文档。
// 请求搜索 year 在 1961~ 1970 (包括 1961 ) 之间的所有书籍
{
"query": {
"bool": {
"must": { "match_all": {} },
"filter": {
"range": {
"year": {
"gte": 1961,
"lte": 1970
}
}
}
}
}
}
//响应结果:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 8,
"successful": 8,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 5,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "books",
"_type": "jinyong",
"_id": "1",
"_score": 1.0,
"_source": {
"title": "射雕英雄传",
"people": [
"郭靖",
"黄蓉",
"杨康",
"穆念慈"],
"year": 1962,
"text": "该小说历史背景突出,场景纷繁,气势宏伟,具有鲜明的“英雄史诗”风格;在人物创
造与情节安排上,它打破了传统武侠小说一味传奇,将人物作为情节附庸的模式,坚持以创造个性化的人物形象为中心,坚
持人物统帅故事,按照人物性格的发展需要及其内在可能性、必然性来设置情节,从而使这部小说达到了事虽奇人却真的妙
境。",
"kongfu": [
"蛤蟆功",
"黯然销魂掌",
"降龙十八掌",
"双手互搏术"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "2",
"_score": 1.0,
"_source": {
"title": "天龙八部",
"people": [
"段誉",
"萧峰",
"虚竹",
"丁春秋"
],
"year": 1962,
"text": "这部小说以宋哲宗时代为背景,通过宋、辽、大理、西夏、吐蕃等王国之间的武林恩
怨和民族矛盾,从哲学的高度对人生和社会进行审视和描写,展示了一幅波澜壮阔的生活画卷。其故事之离奇曲折、涉及人
物之众多、历史背景之广泛、武侠战役之庞大、想象力之丰富当属“金书”之最。作品风格宏伟悲壮,是一部写尽人性、悲剧
色彩浓厚的史诗巨著。",
"kongfu": [
"六脉神剑",
"千蛛万毒手",
"九阴白骨爪",
"化骨绵掌"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "4",
"_score": 1.0,
"_ignored": [
"text.keyword"
],
"_source": {
"title": "倚天屠龙记",
"people": [
"张无忌",
"赵敏",
1.4 邻近匹配
1.4.1match 与 match_phrase
curl -XGET " http://localhost:9200/books/_search "// 创建 << 商品 >> 名称信息的索引。
虽然邻近查询很有用, 但是所有词条都出现在文档的要求过于严格了。
同样的问题: 如果七个词条中有六个匹配, 那么这个文档对用户而言就已经足够相关了, 但是 match_phrase 查
询可能会将它排除在外。
我们可以将一个简单的 match 查询作为一个 must 子句。 这个查询将决定哪些文档需要被包含到结果集中。 我们
可以用 minimum_should_match 参数去除长尾。 然后我们可以以 should 子句的形式添加更多特定查询。 每一个
匹配成功的都会增加匹配文档的相关度。
// demo
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"张翠山",
"殷素素"
],
"year": 1961,
"text": "少林寺觉远禅师看护《楞伽经》不力,导致经书被尹克西和潇湘子盗走。潇湘子和尹
克西互相猜忌残杀,临终之前幡然醒悟,委托何足道向觉远转达经书的下落。何足道接受委托,并向少林寺发出挑战。适逢
郭靖、黄蓉的女儿郭襄前往少林寺寻找杨过,从罗汉掌首座无色禅师处得知何足道挑战少林武功的消息,遂在约定日子只身
前往观战。觉远禅师的弟子张君宝在与何足道一战之中暴露了偷学武功的事实,犯了寺规,受到少林寺众僧的围攻。于是觉
远携张君宝、郭襄突出重围,却在途中圆寂。张君宝与郭襄分手之后,只身前往武当山修学觉远生前传授的九阳真经,并深
得道家冲虚圆通之功的精髓,加以融会贯通,创出了武当一派武功,遂自号三丰。",
"kongfu": [
"太极剑",
"吸星大法",
"七伤拳",
"玄冥神掌"
]
}
}
]
}
}
{
"query": {
"match": {
"text": "在人物创造与情节安排上"
}
}
}"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": 14.441122,
"hits": [
{
"_index": "books",
"_type": "jinyong",
"_id": "1",
"_score": 14.441122,
"_source": {
"title": "射雕英雄传",
"people": [
"郭靖",
"黄蓉",
"杨康",
"穆念慈"
],
"year": 1962,
"text": "该小说历史背景突出,场景纷繁,气势宏伟,具有鲜明的“英雄史诗”风格;在人物创造
与情节安排上,它打破了传统武侠小说一味传奇,将人物作为情节附庸的模式,坚持以创造个性化的人物形象为中心,坚持人
物统帅故事,按照人物性格的发展需要及其内在可能性、必然性来设置情节,从而使这部小说达到了事虽奇人却真的妙境。",
"kongfu": [
"蛤蟆功",
"黯然销魂掌",
"降龙十八掌",
"双手互搏术"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "4",
"_score": 2.0315528,
"_ignored": [
"text.keyword"
],
"_source": {
"title": "倚天屠龙记",
"people": [
"张无忌",
"赵敏",
"张翠山",
"殷素素"
],
"year": 1961,"text": "少林寺觉远禅师看护《楞伽经》不力,导致经书被尹克西和潇湘子盗走。潇湘子和尹克
西互相猜忌残杀,临终之前幡然醒悟,委托何足道向觉远转达经书的下落。何足道接受委托,并向少林寺发出挑战。适逢郭
靖、黄蓉的女儿郭襄前往少林寺寻找杨过,从罗汉掌首座无色禅师处得知何足道挑战少林武功的消息,遂在约定日子只身前往
观战。觉远禅师的弟子张君宝在与何足道一战之中暴露了偷学武功的事实,犯了寺规,受到少林寺众僧的围攻。于是觉远携张
君宝、郭襄突出重围,却在途中圆寂。张君宝与郭襄分手之后,只身前往武当山修学觉远生前传授的九阳真经,并深得道家冲
虚圆通之功的精髓,加以融会贯通,创出了武当一派武功,遂自号三丰。",
"kongfu": [
"太极剑",
"吸星大法",
"七伤拳",
"玄冥神掌"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "2",
"_score": 1.8561981,
"_source": {
"title": "天龙八部",
"people": [
"段誉",
"萧峰",
"虚竹",
"丁春秋"
],
"year": 1962,
"text": "这部小说以宋哲宗时代为背景,通过宋、辽、大理、西夏、吐蕃等王国之间的武林恩怨
和民族矛盾,从哲学的高度对人生和社会进行审视和描写,展示了一幅波澜壮阔的生活画卷。其故事之离奇曲折、涉及人物之
众多、历史背景之广泛、武侠战役之庞大、想象力之丰富当属“金书”之最。作品风格宏伟悲壮,是一部写尽人性、悲剧色彩浓
厚的史诗巨著。",
"kongfu": [
"六脉神剑",
"千蛛万毒手",
"九阴白骨爪",
"化骨绵掌"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "3",
"_score": 0.4352452,
"_source": {
"title": "笑傲江湖",
"people": [
"令狐冲",
"任盈盈",
"岳灵珊",
"林平之"
],"year": 1960,
"text": "福建林远图以七十二路辟邪剑法称雄武林,创立福威镖局,驰骋江湖。远图死后,子孙
无能,四方豪杰纷纷觊觎辟邪剑谱。福威镖局总镖头林震南一门被青城派屠戮殆尽。遗孤林平之拜投华山派掌门君子剑岳不群
门下,一心学艺报仇。",
"kongfu": [
"独孤九剑",
"辟邪剑法",
"葵花宝典",
"七伤拳"
]
}
}
]
}
}
同学可以看到是四条数据那是因为 Elasticsearch 将 " 在人物创造与情节安排上 " 做了分词查询所以我们的查询结果中可
以查询到,所以这种查询方式我们称为全文查询。当然如果同学们需要精确匹配可以使用 match_phrase 。
1.4.2highlight
从字面上意思大家都应该能够理解其中意思 " 高亮 " 这种在实际应用也是在各大收索引擎中是应用非常多的。我们看下
面截图 : 这就是在 highlight 在大数据时代中搜索中的应用,那么在 Elasticsearch 怎么去做这样子的工作。
{
"took": 54,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 3.4595068,
"hits": [
{"_index": "books",
"_type": "jinyong",
"_id": "1",
"_score": 3.4595068,
"_source": {
"title": "射雕英雄传",
"people": [
"郭靖",
"黄蓉",
"杨康",
"穆念慈"
],
"year": 1962,
"text": "该小说历史背景突出,场景纷繁,气势宏伟,具有鲜明的“英雄史诗”风格;在人物创造
与情节安排上,它打破了传统武侠小说一味传奇,将人物作为情节附庸的模式,坚持以创造个性化的人物形象为中心,坚持人
物统帅故事,按照人物性格的发展需要及其内在可能性、必然性来设置情节,从而使这部小说达到了事虽奇人却真的妙境。",
"kongfu": [
"蛤蟆功",
"黯然销魂掌",
"降龙十八掌",
"双手互搏术"
]
},
"highlight": {
"kongfu": [
"<em>蛤</em><em>蟆</em><em>功</em>"
]
}
}
]
}
}
1.4.3聚合查询
在Elasticsearch中eggs表示聚合操作:
{
"aggs": {//聚合操作
"year_group": {//分组名称
"terms": {//分组
"field": "year"//分组字段
}
}
},
"size": 0//去掉原始数据
}
//分组响应结果
{
"took": 28,
"timed_out": false,"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 4,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"year_group": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 1962,
"doc_count": 2
},
{
"key": 1960,
"doc_count": 1
},
{
"key": 1961,
"doc_count": 1
}
]
}
}
}
聚合里面还有其他什么统计方式呢??
1.4.4综合查询中的使用
虽然邻近查询很有用, 但是所有词条都出现在文档的要求过于严格了。
同样的问题: 如果七个词条中有六个匹配, 那么这个文档对用户而言就已经足够相关了, 但是 match_phrase 查
询可能会将它排除在外。
我们可以将一个简单的 match 查询作为一个 must 子句。 这个查询将决定哪些文档需要被包含到结果集中。 我们
可以用 minimum_should_match 参数去除长尾。 然后我们可以以 should 子句的形式添加更多特定查询。 每一个
匹配成功的都会增加匹配文档的相关度。
{
"query": {
"bool": {"must": {
"match": {
"kongfu": {
"query": "独孤九剑",
"minimum_should_match": "30%"
}
}
},
"should": {
"match_phrase": {
"kongfu": {
"query": "太极剑",
"slop": 50
}
}
}
}
}
}
//响应结果
{
"took": 12,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 3,
"relation": "eq"
},
"max_score": 3.703123,
"hits": [
{
"_index": "books",
"_type": "jinyong",
"_id": "3",
"_score": 3.703123,
"_source": {
"title": "笑傲江湖",
"people": [
"令狐冲",
"任盈盈",
"岳灵珊",
"林平之"
],
"year": 1960,
"text": "福建林远图以七十二路辟邪剑法称雄武林,创立福威镖局,驰骋江湖。远图死后,子孙
无能,四方豪杰纷纷觊觎辟邪剑谱。福威镖局总镖头林震南一门被青城派屠戮殆尽。遗孤林平之拜投华山派掌门君子剑岳不群门下,一心学艺报仇。",
"kongfu": [
"独孤九剑",
"辟邪剑法",
"葵花宝典",
"七伤拳"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "4",
"_score": 3.3087118,
"_ignored": [
"text.keyword"
],
"_source": {
"title": "倚天屠龙记",
"people": [
"张无忌",
"赵敏",
"张翠山",
"殷素素"
],
"year": 1961,
"text": "少林寺觉远禅师看护《楞伽经》不力,导致经书被尹克西和潇湘子盗走。潇湘子和尹克
西互相猜忌残杀,临终之前幡然醒悟,委托何足道向觉远转达经书的下落。何足道接受委托,并向少林寺发出挑战。适逢郭
靖、黄蓉的女儿郭襄前往少林寺寻找杨过,从罗汉掌首座无色禅师处得知何足道挑战少林武功的消息,遂在约定日子只身前往
观战。觉远禅师的弟子张君宝在与何足道一战之中暴露了偷学武功的事实,犯了寺规,受到少林寺众僧的围攻。于是觉远携张
君宝、郭襄突出重围,却在途中圆寂。张君宝与郭襄分手之后,只身前往武当山修学觉远生前传授的九阳真经,并深得道家冲
虚圆通之功的精髓,加以融会贯通,创出了武当一派武功,遂自号三丰。",
"kongfu": [
"太极剑",
"吸星大法",
"七伤拳",
"玄冥神掌"
]
}
},
{
"_index": "books",
"_type": "jinyong",
"_id": "2",
"_score": 1.0055228,
"_source": {
"title": "天龙八部",
"people": [
"段誉",
"萧峰",
"虚竹",
"丁春秋"
],"year": 1962,
"text": "这部小说以宋哲宗时代为背景,通过宋、辽、大理、西夏、吐蕃等王国之间的武林恩怨
和民族矛盾,从哲学的高度对人生和社会进行审视和描写,展示了一幅波澜壮阔的生活画卷。其故事之离奇曲折、涉及人物之
众多、历史背景之广泛、武侠战役之庞大、想象力之丰富当属“金书”之最。作品风格宏伟悲壮,是一部写尽人性、悲剧色彩浓
厚的史诗巨著。",
"kongfu": [
"六脉神剑",
"千蛛万毒手",
"九阴白骨爪",
"化骨绵掌"
]
}
}
]
}
}
1.5 映射分词查询
在实际应用中会对我们的文本数据进行相关的管理,有些词可能会进行分词有些可能为关键词不能作为分词信息。
首先我们这边先来对我们的商品信息创建它的:
首先我们创建一个商品的索引:
curl -XPUT " http://localhost:9200/product "// 创建 << 商品 >> 名称信息的索引
// 响应结果:
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "product"
}
curl -XPUT "http://localhost:9200/product/_mapping"//创建<<商品>>信息的结构信息(商品名称,商品价格,商品
库存)。
{
"properties": {//对数据进行约束
"name": {
"type": "text",//文本可分词
"index": true//可索引
},
"price": {
"type": "keyword",//关键词
"index": true//可索引
},
"stock": {
"type": "keyword",//关键词"index": false//不可索引
}
}
}
// 响应结果:
{
"acknowledged": true
}
//那么我们现在创建了商品为索引的结构体信息那么,现在我们对product,来创建信息。
curl -XPUT "http://localhost:9200/product/_create/10001" //创建商品信息
{
"name": "我是价格为50元的衣服我哦还有100件",
"price": 50,
"stock": 100
}
{
"_index": "product",
"_type": "_doc",
"_id": "10001",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
接下来我们来看下查询:
curl -XPUT "http://localhost:9200/product/_search" //查询名称包含衣服的数据
{
"query":{
"match": {
"name":"衣服"
}
}
}
{
"took": 1030,
"timed_out": false,"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.5753642,
"hits": [
{
"_index": "product",
"_type": "_doc",
"_id": "10001",
"_score": 0.5753642,
"_source": {
"name": "我是价格为50元的衣服我哦还有100件",
"price": 50,
"stock": 100
}
}
]
}
}
keyword 的设置这里根据类推,这里同学们思考下会是什么样子的结构查询。
2. 基于 Elasticsearch 分析用户行为
2.1 背景介绍
根据用户输入和筛选条件进行搜索后,有时返回的是无结果或者结果很少的情况,为了提升用户搜索体验,需要能够
给用户推荐一些相关的搜索词,比如用户搜索【张无忌】时没有找到相关的 任务,可以推荐搜索【玄冥神掌】、
【七伤拳】等关键词。
2.2 设计思路
首先需要分析搜索无结果或者结果过少可能的原因,我总结了一下,主要包括主要可能:
1. 搜索的关键词在本网不存在,比如【金毛狮王】;
2. 搜索的关键词在本网的文本很少,比如【小说】;
3. 搜索的关键词拼写有问题,比如把【九阴白骨爪】写成了【九荫白骨抓】;
那么针对以上情况,可以采用以下方式进行处理: 1. 搜索的关键词在本网不存在,可以通过爬虫的方式获取相关知识,然后根据 搜索建议词 去提取,比如去百度百
科的【金毛狮王】词条里就能提取出【七伤拳】、【张无忌】和【谢逊】等关键词;当然基于爬虫的知识可能
存在偏差,此时需要能够有人工审核或人工更正的部分;
2. 搜索的关键词在本网的商品很少,有两种解决思路,一种是通过方式 1 的爬虫去提取关键词,另外一种是通过返
回商品的信息去聚合出关键词,如书籍、武功、风格、标签等,这里我们采用的是后者(在测试后发现后者效
果更佳);
3. 搜索的关键词拼写有问题,这就需要 拼写纠错 出场了,先纠错然后根据纠错后的词去提供搜索推荐;
4. 搜索的关键词过多,有两种解决思路,一种是识别关键词的类型,如是品牌、品类、风格还是性别,然后通过
一定的组合策略来实现搜索推荐;另外一种则是根据用户的输入到搜索建议词里去匹配,设置最小匹配为一个
匹配到一个 Term 即可,这种方式实现比较简单而且效果也不错,所以我们采用的是后者。
所以,我们在实现搜索推荐的核心是之前讲到的搜索建议词,它提供了本网主要的关键词,另外一个很重要的是它本
身包含了 关联作品的属性 ,这样就可以保证推荐给用户的关键词是可以搜索出结果的。
这里列取相关字段的索引:
{
"mappings": {
"suggest": {
"properties": {
"keyword": {
"fields": {
"keyword": {
"type": "string",
"index": "not_analyzed"
},
"keyword_lowercase": {
"type": "string",
"analyzer": "lowercase_keyword"
},
"keyword_ik": {
"type": "string",
"analyzer": "ik_smart"
},
"keyword_pinyin": {
"type": "string",
"analyzer": "pinyin_analyzer"
},
"keyword_first_py": {
"type": "string",
"analyzer": "pinyin_first_letter_keyword_analyzer"
}
},
"type": "multi_field"
},
"type": {
"type": "long"
},
"weight": {
"type": "long"
},
"count": {
"type": "long"}
}
}
}
}
书籍数据索引
{
"mappings": {
"books": {
"properties": {
"jinyong": {
"type": "long"
},
"title": {
"type": "string",
"analyzer": "ik_smart"
},
"people": {
"type": "string",
"analyzer": "ik_smart"
},
"kongfu": {
"type": "string",
"analyzer": "ik_smart"
}
}
}
}
}
关键词映射索引
主要就是source和dest直接的映射关系。
PUT /conversion_index
{
"mappings": {
"conversion": {
"properties": {
"source": {
"type": "string",
"analyzer": "lowercase_keyword"
},
"dest": {
"type": "string",
"index": "not_analyzed"
}
}
}}
}
2.3 搜索建议实现
在我们的搜索建议实现里,主要考虑了建议词的来源、匹配、排序、关联的作品名称和拼写纠错。
SuggestionDiscovery
SuggestionDiscovery 的职责是发现建议词;
建议词的来源可以是商品的作品名称、作者名称、作品标签、作品名称的高频词、热搜词,也可以是一些组合
词,比如 “ 分类 + 性别 ” 和 “ 分类 + 标签 ” ,还可以是一些自定义添加的词;
建议词维护的时候需要考虑去重,比如 “ 倚天屠龙记 ” 和 “ 倚天屠龙 记 ” 应该是相同的, “ 金毛狮王 ” 和 “ 谢逊 ” 也应该
是相同的;
由于建议词的来源通常比较稳定,所以执行的周期可以比较长一点,比如每周一次;
SuggestionCounter
SuggestionCounter 的职责是获取建议词关联的作品,如果需要可以进行一些聚合操作,比如聚合分类和标
签;
SuggestionCounter 的实现的时候由于要真正地调用搜索接口,应该尽量避免对用户搜索的影响,比如在凌晨
执行并且使用单线程调用;
为了提升效率,应该使用 Elasticsearch 的 Multi Search 接口批量进行 count ,同时批量更新数据库里建议词的
count 值;
由于 SuggestionCounter 是比较耗资源的,可以考虑延长执行的周期,但是这可能会带来 count 值与实际搜索时
误差较大的问题,这个需要根据实际情况考虑;
SuggestionIndexRebuiler
SuggestionIndexRebuiler 的职责是负责重建索引;
考虑到用户的搜索习惯,可以使用 Multi-fifields 来给建议词增加多个分析器。比如对于【小说 文章】的建议词使
用 Multi-fifields 增加不分词字段、拼音分词字段、拼音首字母分词字段、分词字段,这样输入【金庸】和
【 jinyong 】都可以匹配到该建议词;
重建索引时通过是通过 bulk 批量添加到临时索引中,然后通过别名来更新;
重建索引的数据依赖于 SuggestionCounter ,因此其执行的周期应该与 SuggestionCounter 保持一致;
SuggestionService
SuggestionService 是真正处于用户搜索建议的服务类;
通常的实现是先到缓存中查询是否能匹配到缓存记录,如果能匹配到则直接返回;否则的话调用 Elasticsearch
的 Prefifix Query 进行搜索,由于我们在重建索引的时候定义了 Multi-fifields ,在搜索的时候应该用 boolQuery 来
处理;如果此时 Elasticsearch 返回不为空的结果数据,那么加入缓存并返回即可;
3.Elasticsearch 应用
3.1 使用 Elasticsearch 作为我们后台的文本搜索工具
索引擎是部署在成熟的数据存储的顶部,以提供快速且相关的搜索能力。这是因为早期的搜索引擎不能提供耐用的存
储或其他经常需要的功能,如统计。 Elasticsearch 是提供持久存储、统计等多项功能的现代搜索引擎。 如果你开始一个新项目,我们建议您考虑使用
Elasticsearch 作为唯一的数据存储,以帮助保持你的设计尽可能简单。 此种场景不支持包含频繁更新、事务
( transaction )的操作。
举例如下:新建一个博客系统使用 es 作为存储。 1. 我们可以向 ES 提交新的大量文本信息; 2. 使用 ES 检索、搜索、统
计数据。
ES 作为存储的优势: 如果一台服务器出现故障时会发生什么?你可以通过复制 数据到不同的服务器以达到容错的目
的。 注意: 整体架构设计时,需要我们权衡是否有必要增加额外的存储。
3.2 在现有系统中增加 elasticsearch
由于 ES 不能提供存储的所有功能,一些场景下需要在现有系统数据存储的基础上新增 ES 支持。
举例 1 : ES 不支持事务、复杂的关系(至少 1.X 版本不支持, 2.X 有改善,但支持的仍然不好),如果你的系统中需要
上述特征的支持,需要考虑在原有架构、原有存储的基础上的新增 ES 的支持。 举例 2 :如果你已经有一个在运行的复杂的系统,你的需求之一是在现有系统中添加检索服务。一种非常冒险的方式
是重构系统以支持 ES 。而相对安全的方式是:将 ES 作为新的组件添加到现有系统中。 如果你使用了如下图所示的
SQL 数据库和 ES 存储,你需要找到一种方式使得两存储之间实时同步。需要根据数据的组成、数据库选择对应的同步
插件。可供选择的插件包括: 1 ) mysql 、 oracle 选择 logstash-input-jdbc 插件。 2 ) mongo 选择 mongo
connector 工具。
假设你的在线零售商店的产品信息存储在 SQL 数据库中。 为了快速且相关的搜索,你安装 Elasticsearch 。 为了索引
数据,您需要部署一个同步机制,该同步机制可以是 Elasticsearch 插件或你建立一个自定义的服务。此同步机制可以
将对应于每个产品的所有数据和索引都存储在 Elasticsearch ,每个产品作为一个 document 存储(这里的 document
相当于关系型数据库中的一行 /row 数据)。
当在该网页上的搜索条件中输入 “ 用户的类型 ” ,店面网络应用程序通过 Elasticsearch 查询该信息。 Elasticsearch 返回
符合标准的产品 documents ,并根据你喜欢的方式来分类文档。 排序可以根据每个产品的被搜索次数所得到的相关
分数,或任何存储在产品 document 信息,例如:最新最近加入的产品、平均得分,或者是那些插入或更新信息。 所
以你可以只使用 Elasticsearch 处理搜索。这取决于同步机制来保持 Elasticsearch 获取最新变化。
3.3 使用 elasticsearch 和现有的工具
在工作中我们需要把数据展现出来,就能通过 elasticssearch 完成一项工作。很多工具都可以与 Elasticsearch 一起工
作,我们没有必要在去编写它的可视化工具。
需要部署一个大规模的日志框架存储,搜索,并分析了大量的事件。 如果处理处理日志和输出到 Elasticsearch ,您
可以使用日志记录工具。
1.rsyslog ( www.rsyslog.com ),
2.Logstash ( www.elastic.co/products/logstash )
3.Apache Flume ( http://flflume.apache.org )。
可视化工具 :
Kibana ( www.elastic.co/cn/kibana )。
在开发工具中我们也是可以用来做我们的数据调试: 3.4 使用 elasticsearch 解决订单数据
显然只通过 DB 来支撑大量的查询是不可取的,同时对于一些复杂的查询, Mysql 支持得不够友好,所以 Elasticsearch
分布式搜索储存集群的引入,就是为了解决订单数据的存储与搜索的问题。
对订单模型进行抽象和分类,将常用搜索字段和基础属性字段剥离。 DB 做分库分表,存储订单详情; Elasticsearch
存储搜素字段。
为了解决商品订单数据存储,复杂查询,我们看下图: