我们的编程思路是:
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索引实现大数据搜索——之编程实现(三)中实现