python下建立elasticsearch索引实现大数据搜索——之编程实现(二)

我们的编程思路是:

1.首先根据用户的需求提出的主图案,颜色,技法,我们应该在素材resource表中找到包含有这三种需求的素材list

2.然后根据素材list的每一个素材,在设计图stylepatternshow表中找到包含有该种素材的设计图

所以总体上需要两个类,一个是ElasticMaterialObj类,能够根据需求找到素材list;另一个是ElasticGraphObj类,能够根据素材list推荐出设计图。每个类基本上有这些方法:

1)__init__ :初始化方法,初始化在elasticsearch(下面简称es)建立的索引名,索引类型,服务器ip(这里我先采用本地测试ip默认为127.0.0.1)

2)create_index:创建索引方法,根据索引名,索引类型在es中创建出索引

3)bulk_Index_Data:批量导入数据,把数据导入建立的索引中(说明一下,这里我先采用:人工操作,从ssh穿透服务器下载数据到本地成json格式文件,后面,我会展示如何从ssh穿透的阿里云内网rdb中取得数据

4)get_Data_By_Body:根据查询body取得数据

为了能够让python连接上es,必须确保你开启了es服务,如下:

启动Elasticsearch

进入/usr/local/elasticsearch目录之中,输入以下命令,开始Elasticsearch服务

./bin/elasticsearch

 

1.导入相关类

#coding=utf-8
from elasticsearch import Elasticsearch  '''和es建立连接'''
from elasticsearch.helpers import bulk    '''批量导入数据'''
from elasticsearch.helpers import scan    '''获取大量数据,es默认获取10条结果'''
import json

2. ElasticMaterialObj类

  • 2.1 __init__方法
 def __init__(self,index_name,index_type,ip="127.0.0.1"):
        '''
        :param index_name: 索引名
        :param index_type: 索引类型
        :param ip: ip
        '''
        self.index_name = index_name
        self.index_type = index_type
        # 无用户名密码状态
        self.esObj = Elasticsearch([ip])  '''和es建立连接,important'''
        # 用户名密码状态
        # self.esObj = Elasticsearch([ip],http_auth=('elastic', 'password'),port=9200)
  • 2.2 create_index方法
 def create_index(self,index_name='resource',index_type='resource_type'):
        '''
        创建索引,创建索引名称为resource,类型为resource_type的索引
        :param index_name:
        :param index_type:
        :return:
        '''
        # 创建索引
        _index_mappings = {
            "mappings": {
                self.index_type: {
                    "properties": {
                        "id": {
                            "type": "long",
                            "index": "false"
                        },
                        "serial": {
                            "type": "keyword",  # keyword不会进行分词,text会分词
                            "index": "false"  # 不建索引
                        },
                        #tags可以存json格式,访问tags.content
                        "tags": {
                            "type": "object",
                            "properties": {
                                "content": {"type": "keyword", "index": True},
                                "dominant_color_name": {"type": "keyword", "index": True},
                                "skill": {"type": "keyword", "index": True},
                            }
                        },
                        "hasTag": {
                            "type": "long",
                            "index": True
                        },
                        "status": {
                            "type": "long",
                            "index": True
                        },
                        "createTime": {
                            "type": "date",
                            "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
                        },
                        "updateTime": {
                            "type": "date",
                            "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
                        }
                    }
                }
            }
        }
        if self.esObj.indices.exists(index = self.index_name) is not True:
            res = self.esObj.indices.create(index = self.index_name,body = _index_mappings)
             print('index is create->',res)
        else:
            print('index is already exist')

 注:建立索引比较重要的是mapping的创建,这是根据你的需求建立的,我也没法讲啥,多找些资料,看会mapping建立的语法。关键的建立索引的语法是self.esObj.indices.create(index = self.index_name,body = _index_mappings)

题外话:

这一步建立成功后,你在浏览器键入:

http://localhost:9200/_cat/indices?v

此时你就能看到你建立的索引名在index目录里

 

 如果你在浏览器键入:

http://localhost:9200/你的索引名

此时你就能看到你建立的索引的mappings以及settings

  • 2.3 bulk_Index_Data方法
   def bulk_Index_Data(self,jsonFile):
        '''
        用bulk将批量数据存储到es
        :return:
        '''
        with open(jsonFile, 'r') as load_f:
            load_json = json.load(load_f)
        ACTIONS =[]
        i = 1
        for line in load_json:
             #=====================================================
            if line['type'] == 'MATERIAL' and line['hasTag'] == 1 and line['status'] == 1:
                tags_dict = eval(line['tags'])
                content,dominant_color_name,skill = self.get_data_from_dict(tags_dict)
                if content==[]:
                    continue
             #这一部分不用管,是我进行处理数据。你需要根据你的数据字段拿到相应数据
            #======================================================
            
     '''这一部分action才是你需要改的,根据你建的mappings字段,把相应数据写到key-values中'''
                action ={
                    "_index": self.index_name,
                    "_type": self.index_type,
                    "_id": i, #_id 也可以默认生成,不赋值
                    "_source":{
                        "id": line['id'],
                        "serial":line['serial'],
                        "tags.content" :content[0],
                        "tags.dominant_color_name": dominant_color_name,
                        "tags.skill": skill,
                        "hasTag":line['hasTag'],
                        "status":line['status'],
                        "createTime" :line['createTime'],
                        "updateTime":line['updateTime'],
                    }
                }
                i += 1
                '''构成一整个dict的list'''
                ACTIONS.append(action)
         '''主要的方法:bulk'''
        success, _ = bulk(self.esObj, ACTIONS, index=self.index_name, raise_on_error=True)
        print('Performed %d actions' % success)

注:可以看到,这里最主要的方法是bulk(self.esObj, ACTIONS, index=self.index_name, raise_on_error=True)

  • 2.4 get_Data_By_Body方法
   def get_Data_By_Body(self,content,color,skill,match_num):
        #这里是三个分别去查找,考虑了一下,综合的去查找更好
        # doc_content = {"query": {"match": {"tags.content": content}}}
        # doc_color = {"query": {"match": {"tags.dominant_color_name": color}}}
        # doc_skill = {"query": {"match": {"tags.skill": skill}}}
        doc_combine = {
            "query":{
                "bool":{
                    "should":[
                        {"match":{"tags.content": content}},
                        {"match": {"tags.dominant_color_name": color}},
                        {"match": {"tags.skill": skill}}
                   ],
                    "minimum_should_match":match_num
                }
            }
        }
        material_serial_list = self.get_single_serial(doc_combine)
        # print(material_serial_list)
        return material_serial_list

    def get_single_serial(self,doc):
        scanResp = scan(client=self.esObj,query=doc,scroll="10m",preserve_order=False)
        i=0
        serial_list = []
        for resp in scanResp:
            serial_list.append(resp['_source']['serial'])
            i += 1
        # print('match total:%d'%i)
        return serial_list

注:这个方法是最主要的,根据输入的需求,直接得到素材list(‘serial’号字段表示唯一素材标识),最主要你的方法是:scanResp = scan(client=self.esObj,query=doc,scroll="10m",preserve_order=False),如果用search方法,只能得到10条数据

=========================================================================================

上面已经实现了素材类的编写,能够根据需求:主图案,颜色,技法  得到包含这些的material list,调用如下:

def main():
    es = ElasticMaterialObj('resource','resource',ip='127.0.0.1')
    if es.esObj.indices.exists(index=es.index_name) is not True:
         es.create_index()
         es.bulk_Index_Data('./design_resource.json')
    material_serial_list = es.get_Data_By_Body('月季','黄色','水墨画',3)
main()

而设计图类的编写方式差不多,区别在于建立的索引,存储数据,根据body查询不同,这将在python下建立elasticsearch索引实现大数据搜索——之编程实现(三)中实现

猜你喜欢

转载自blog.csdn.net/m0_37673307/article/details/81153141