基本情况就是,媒体、试题、分类,媒体可能有多个试题,一个试题可能有多个分类,分类为三级分类加上一个综合属性。通过试题名称、分类等搜索查询媒体。

现在的问题为,搜索结果不精确,部分搜索无结果,ES的数据结构不满足搜索需求。解决方案就是,重构ES数据结构,采用父子关系的方式,建立media和question两个type。

全程使用https://github.com/mobz/elasticsearch-head,这个进行ES的管理和查看,很方便。

从ES的说明可以看出,ES是面向文档,其实所有的数据都是一张张卡片,例如下面这个:

几个重要的概念:mapping,index,type可以直接参考上图:

_index,可以看做是数据库吧,上图命名为links,在对搜索进行操作的时候需要指定,就像指定数据库一样。

_type,约等于表,例如这里的media,上图的_type列大家还可以看到有question数值。其实就等于我们的media表和question表

mapping,映射、绘制...的地图,顾名思义。其实就是表结构和表关系。例如上面点开的卡片内,_source内有id,language等,其实就是mapping。mapping还包括关系的定义,例如这里的media是parent父级,question的结构创建的时候就需要指定_parent为media。

了解了以上几个概念,我们就可以进行结构创建了。就像数据库一样,我们需要一个media表,放媒体信息,媒体ID作为唯一的ID。然后question表,放question的信息(这里还包括试题的分类),我们把同一个试题分配为不同分类也算作不同试题。这里这样的结构,也是为了根据多级分类搜索的时候方便而设置的,下面说搜索的时候会挑明。

这是初始化创建index和mapping的代码:

$elasticaClient = new \Elastica\Client(array('host'=>'localhost','port'=>9200));

// Load index

$elasticaIndex = $elasticaClient->getIndex('links');

// Create the index new

// 创建index的参数自行参见官网,就不一一解释了

$elasticaIndex->create(

array(

'number_of_shards' => 4,

'number_of_replicas' => 1,

'analysis' => array(

'analyzer' => array(

'indexAnalyzer' => array(

'type' => 'custom',

'tokenizer' => 'standard',

'filter' => array('lowercase', 'mySnowball')

),

'searchAnalyzer' => array(

'type' => 'custom',

'tokenizer' => 'standard',

'filter' => array('standard', 'lowercase', 'mySnowball')

)

),

'filter' => array(

'mySnowball' => array(

'type' => 'snowball',

'language' => 'German'

)

)

)

),

true

);

//创建media的mapping,作为父级

$mediaType = $elasticaIndex->getType('media');

// Define mapping

$mapping = new \Elastica\Type\Mapping();

$mapping->setType($mediaType);

$mapping->setParam('index_analyzer', 'indexAnalyzer');

$mapping->setParam('search_analyzer', 'searchAnalyzer');

// Define boost field

$mapping->setParam('_boost', array('name' => '_boost', 'null_value' => 1.0));

// Set mapping

// 定义media的字段和属性

$mapping->setProperties(array(

'id'      => array('type' => 'string', 'include_in_all' => FALSE),

'media_name'     => array('type' => 'string', 'include_in_all' => TRUE),

'tstamp'  => array('type' => 'date', 'include_in_all' => FALSE),

'language' => array('type' => 'integer', 'include_in_all' => FALSE),

'_boost'  => array('type' => 'float', 'include_in_all' => FALSE)

));

// Send mapping to type

// 保存media的mapping

$mapping->send();

//创建question的mapping,父级为media

$questionType = $elasticaIndex->getType('question');

// Define mapping

$mapping = new \Elastica\Type\Mapping();

$mapping->setType($questionType);

$mapping->setParam('index_analyzer', 'indexAnalyzer');

$mapping->setParam('search_analyzer', 'searchAnalyzer');

// Define boost field

$mapping->setParam('_boost', array('name' => '_boost', 'null_value' => 1.0));

// Set mapping

// question的字段和属性

$mapping->setProperties(array(

'id'      => array('type' => 'string', 'include_in_all' => FALSE),

'level_one'      => array('type' => 'integer', 'include_in_all' => FALSE),

'level_two'      => array('type' => 'integer', 'include_in_all' => FALSE),

'level_thr'      => array('type' => 'integer', 'include_in_all' => FALSE),

'top_level'      => array('type' => 'string', 'include_in_all' => FALSE),

'cat_id'      => array('type' => 'integer', 'include_in_all' => FALSE),

'quest_hash'      => array('type' => 'string', 'include_in_all' => TRUE),

'content'     => array('type' => 'string', 'include_in_all' => TRUE),

'view_num'      => array('type' => 'integer', 'include_in_all' => FALSE),

'like_num'      => array('type' => 'integer', 'include_in_all' => FALSE),

'_boost'  => array('type' => 'float', 'include_in_all' => FALSE)

));

$mapping->setParent("media");//指定question的父类

// Send mapping to type

// 保存question的mapping

$mapping->send();

上面虽然是PHP代码,但是最终生成的也是一个url请求。

下面说搜索,搜索的话ES是通过query、filter等来处理的,query里面有很多不同的方式,参见:http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-queries.html,filter也是,参见http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-filters.html

这里搜索是这样的,根据media的media_name做query_string搜索,然后对media进行has_child的filter搜索,has_child搜索内使用boolAnd的filter来筛选。

下面是搜索的代码:

$query = new \Elastica\Query();

if (!empty($input['key'])) {

//针对media的media_name字段设置QueryString查询

$elasticaQueryString  = new \Elastica\Query\QueryString();

$elasticaQueryString->setFields(array("media.media_name"));

$elasticaQueryString->setQuery($input['key']);

//

$query->setQuery($elasticaQueryString);

}else {

$query->setQuery(new MatchAll()); //命中全部纪录

}

$language_bool = false;

$elasticaFilterAnd = new \Elastica\Filter\BoolAnd();

//language也是针对media,设置BoolAnd查询

if (isset($input['language']) && !empty($input['language'])) {

$filterl1 = new \Elastica\Filter\Term();

$filterl1->setTerm('language', intval($input['language']));

$elasticaFilterAnd->addFilter($filterl1);

$language_bool = true;

}

//

//对子集进行筛选查询,使用has_child

$subFilterAnd = new \Elastica\Filter\BoolAnd();

$bool = false;

// 一级分类条件

if (isset($input['level_one']) && !empty($input['level_one'])) {

$filterl1 = new \Elastica\Filter\Term();

$filterl1->setTerm('level_one', intval($input['level_one']));

$subFilterAnd->addFilter($filterl1);

$bool = true;

}

// 二级分类条件

if (isset($input['level_two']) && !empty($input['level_two'])) {

$filterl1 = new \Elastica\Filter\Term();

$filterl1->setTerm('level_two', intval($input['level_two']));

$subFilterAnd->addFilter($filterl1);

$bool = true;

}

// 三级分类条件

if (isset($input['level_thr']) && !empty($input['level_thr'])) {

$filterl1 = new \Elastica\Filter\Term();

$filterl1->setTerm('level_thr', intval($input['level_thr']));

$subFilterAnd->addFilter($filterl1);

$bool = true;

}

// 直接指定分类ID查询

if (isset($input['cat_id']) && !empty($input['cat_id'])) {

$filterl1 = new \Elastica\Filter\Term();

$filterl1->setTerm('cat_id', intval($input['cat_id']));

$subFilterAnd->addFilter($filterl1);

$bool = true;

}

// 分类属性查询

if (isset($input['top_level']) && !empty($input['top_level'])) {

$filterl1 = new \Elastica\Filter\Term();

$filterl1->setTerm('top_level', $input['top_level']);

$subFilterAnd->addFilter($filterl1);

$bool = true;

}

if($bool){

// 声明一个查询,用于放入子查询

$subQuery = new \Elastica\Query();

// 使用filteredquery,融合query和filter

$filteredQuery = new \Elastica\Query\Filtered(new MatchAll(),$subFilterAnd);

// 添加filterquery到子查询

$subQuery->setQuery($filteredQuery);

// 声明hasChildFilter,声明的时候就指定子查询的内容,指定查询的子表(也就是TYPE)为question

$filterHasChild = new \Elastica\Filter\HasChild($subQuery,"question");

// 将拥有子类查询增加到父级查询的filter中

$elasticaFilterAnd->addFilter($filterHasChild);

}

if($bool || $language_bool){

// 将filter增加到父查询汇中

$query->setFilter($elasticaFilterAnd);

}

//

//

$query->setFrom($start);    // Where to start?

$query->setLimit($limit);   // How many?

//

//Search on the index.

$elasticaResultSet = $elasticaIndex->search($query);

上面看上去很长的PHP代码,其实最后发出的时候也只是一个发送json数据的请求,对照下面这个json数据和上面的代码,大家就很容易明白了:

{

"query": {

"query_string": {

"query": "like",

"fields": [

"media.media_name"

]

}

},

"filter": {

"and": [

{

"term": {

"language": 1

}

},

{

"has_child": {

"query": {

"filtered": {

"query": {

"match_all": {}

},

"filter": {

"and": [

{

"term": {

"top_level": "111"

}

}

]

}

}

},

"type": "question"

}

}

]

},

"from": 0,

"size": 20

}

总结:ES很强大,不仅仅是在导入性能还是搜索性能,或者是搜索结果,或者是结构的调整上来说。作为刚接触不久的也能很快的进行数据结构重构并重写搜索,还是算比较好的。唯一的缺点就是,中文的文档太少,需要不断的使用谷歌来查看文档、去官网看文档说明、看PHP的API。

在处理过程中,感谢之前的哥们留下的代码,至少不是摸瞎。感谢同事搞的谷歌搜索,一般人我不告诉他,大家可以去试试 另客网,首页的搜索框里面,选择谷歌。

个人笔记,写来大家分享分享,肯定有不足错误的,欢迎大家指出,谢谢。

elasticsearch php搜索,网站基于ElasticSearch搜索的优化笔记 PHP相关推荐

  1. 谷歌搜索网站流量_Google搜索升级使网站更难赢得流量

    谷歌搜索网站流量 By Gerrit De Vynck 杰里特·德温克(Gerrit De Vynck) Type a query into the Google search bar on a sm ...

  2. 网站基于文本搜索的实现

    源码如下 <?php             $dispstr=array();             $dispstr[1]="disp_os.php?article_id=&qu ...

  3. 多个搜索引擎搜索网站,提高搜索效率,快人一步

    网站地址如下: https://www.elubiao.com/ 一路飙 http://www.duoci.com/ 多次搜 (比较喜欢这个) https://search.chongbuluo.co ...

  4. 了解学习 Elasticsearch 及其与 Python 实现全文搜索

    Elasticsearch简介 ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用 ...

  5. 几个很特别的音乐搜索网站

    几个很特别的音乐搜索网站 关键词: 搜索 音乐 网站 ┊ 杂粹 ┊ 推荐: ┊ 来源: 有意思吧 ┊ 收藏 随着网络越来越深入我们的生活,我们会经常使用一些搜索引擎来搜索自己想要的歌曲,比如百度MP3 ...

  6. 免费分享6个资源搜索网站,不怕资源搜不到,没多少人知道这些

    1.西林街搜索 西林街搜索,这个网站专注于盘类资源搜索,可以搜索各种文库.学术资料.视频.教程.音乐等,网站整体看起来十分简洁,而且主页的背景图片也会隔段时间自动更换. 网站链接↑↑↑ http:// ...

  7. 个人网页中利用表单实现跳转B站和QQ音乐搜索(仿百度搜索)

    HTML利用标签接入B站搜索功能 最近在制作个人网页的时候,想在网站中插入两个搜索接口,一个用来对接B站**搜索视频,另一个用来对接QQ音乐,搜索音乐. 搜索了一下后发现有使用百度进行搜索的例子: 利 ...

  8. 基于Elasticsearch实现搜索建议

    搜索建议是搜索的一个重要组成部分,一个搜索建议的实现通常需要考虑建议词的来源.匹配.排序.聚合.关联的文档数和拼写纠错等,本文介绍一个基于Elasticsearch实现的搜索建议. 问题描述 电商网站 ...

  9. 基于Elasticsearch实现搜索推荐

    在基于Elasticsearch实现搜索建议一文中我们曾经介绍过如何基于Elasticsearch来实现搜索建议,而本文是在此基于上进一步优化搜索体验,在当搜索无结果或结果过少时提供推荐搜索词给用户. ...

最新文章

  1. 在 RedHat 使用 gdc-client 下载 TCGA 数据
  2. 网站优化助力网站在同行中更加出类拔萃
  3. caffe 练习1:training LeNet on MNIST with Caffe/ 用LeNet识别手写字符集 Mnist------by 香蕉麦乐迪
  4. ASP中怎么实现SQL数据库备份、恢复!
  5. 『信息收集』GoogleHacking快速定位目标网站
  6. Educational Codeforces Round 64(Unrated for Div.1+Div. 2)
  7. FCKeditor的开发精简
  8. 用来表示python代码块的是什么_三分钟带你用简单的Python代码深入理解Python中的元类...
  9. PyRun_SimpleString的无穷怨念
  10. python定时任务框架_Python定时任务框架APScheduler
  11. 使用case语句的3个诀窍
  12. C++内存管理变革(3):另类内存管理
  13. Spring框架IOC的实现
  14. 标准C语言第四版答案第十章,谭浩强C语言 第十章课后习题
  15. 计算机如何实现截长图功能,只会Ctrl+Alt+A?告诉你电脑截长图的5大方法
  16. 怎么开发qq群自动回复机器人呢?我教你
  17. 祝贺swm8023刷HDU-Steps登顶+突破新Section,14.2不是传说中的高级计算几何,而是数学~~...
  18. 【OCP】小麦苗OCP(包括11g、12c、18c、19c等)网络班早已开讲,注重实践,报名一次,终身可免费升级学习,推荐有红包...
  19. 查找——图文翔解SkipList(跳跃表)
  20. android回传数据实验报告,传热综合实验实验报告.doc

热门文章

  1. 图神经网络发展进程,深度神经网络发展
  2. Node.js以及cn-moble安装
  3. 【个人Onenote笔记】整理+搬运
  4. css添加div阴影
  5. 数据可视化—D3力导向图—如何实现结点与其连线的交互
  6. 词汇难关 记忆雅思单词20个经典方法特别推荐
  7. c语言走迷宫游戏代码
  8. 查看CAD建筑图纸有什么技巧?怎么快速实现CAD看图呢?
  9. 顶级数据科学家谈数据素养
  10. 大局视角看上海,数据集团定乾坤!