搜索引擎优化定义(为什么说一个试题是多个index,而question却是question?)

优采云 发布时间: 2021-09-28 17:43

  搜索引擎优化定义(为什么说一个试题是多个index,而question却是question?)

  基本情况是媒体、试题和分类。媒体可能有多个试题,一个试题可能有多个类别。分类是三级类别加综合属性。通过测试标题、分类等方式搜索和查询媒体。

  目前的问题是搜索结果不准确,有的搜索没有结果。ES的数据结构不符合搜索要求。解决方案是重构ES数据结构,采用父子关系,建立媒体和问题两种类型。

  在整个过程中使用它。ES的管理和查看非常方便。

  从ES的描述可以看出,ES是面向文档的。其实所有的数据都是卡片,比如下面这些:

  

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

  _index,可以看作是一个数据库,上图是命名链接,操作搜索时需要指定,就像指定数据库一样。

  _type 大约等于 table,比如这里的 media。也可以在上图中的_type列中看到问题值。其实就等于我们的媒体表和问题表

  映射,映射,绘制地图...,顾名思义。其实就是表结构和表关系。比如上面点击的卡片,_source里面有id,language等,其实就是mapping。映射还包括关系的定义。例如,这里的媒体是父父级。创建问题结构时,需要指定 _parent 作为媒体。

  理解了上面的概念之后,我们就可以创建结构了。就像数据库一样,我们需要一个媒体表来保存媒体信息,媒体ID就是唯一ID。然后是题表,放题信息(这里也包括试题的分类),我们把同一个试题分到不同的类别,算作不同的试题。这里的结构也是为了方便基于多级分类的搜索而设置的。搜索时将突出显示以下内容。

  这是初始化创建索引和映射的代码:

      $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有很多种不同的方式,见:,filter也见

  这里的搜索是这样的。根据media的media_name做一个query_string搜索,然后对media进行has_child过滤搜索,在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非常强大,不仅是导入性能或者搜索性能,或者搜索结果,或者结构调整。作为一个能快速重构数据结构,重写搜索的新手,还是比较不错的。唯一的缺点就是中文文档太少了,需要不断的用google查看文档,去官网看文档,看PHP API。

  部分参考来自这里:

  从:

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线