Skip to content

Commit 8bb4a58

Browse files
committed
fix
1 parent bc8bd0d commit 8bb4a58

2 files changed

+354
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
## Elasticsearch 基本概念
2+
3+
Index:Elasticsearch用来存储数据的逻辑区域,它类似于关系型数据库中的database 概念。一个index可以在一个或者多个shard上面,同时一个shard也可能会有多个replicas。
4+
5+
Document:Elasticsearch里面存储的实体数据,类似于关系数据中一个table里面的一行数据。
6+
7+
document由多个field组成,不同的document里面同名的field一定具有相同的类型。document里面field可以重复出现,也就是一个field会有多个值,即multivalued。
8+
9+
Document type:为了查询需要,一个index可能会有多种document,也就是document type. 它类似于关系型数据库中的 table 概念。但需要注意,不同document里面同名的field一定要是相同类型的。
10+
11+
Mapping:它类似于关系型数据库中的 schema 定义概念。存储field的相关映射信息,不同document type会有不同的mapping。
12+
13+
下图是ElasticSearch和关系型数据库的一些术语比较:
14+
15+
16+
17+
Relationnal database | Elasticsearch
18+
---|---
19+
Database| Index
20+
Table | Type
21+
Row | Document
22+
Column | Field
23+
Schema | Mapping
24+
Schema | Mapping
25+
Index | Everything is indexed
26+
SQL | Query DSL
27+
SELECT * FROM table… | GET http://…
28+
UPDATE table SET | PUT http://…
29+
30+
31+
## Python Elasticsearch DSL 使用简介
32+
33+
连接 Es:
34+
35+
```python
36+
import elasticsearch
37+
38+
es = elasticsearch.Elasticsearch([{'host': '127.0.0.1', 'port': 9200}])
39+
```
40+
41+
先看一下搜索,`q` 是指搜索内容,空格对 `q` 查询结果没有影响,`size` 指定个数,`from_` 指定起始位置,`filter_path` 可以指定需要显示的数据,如本例中显示在最后的结果中的只有 `_id``_type`
42+
43+
```python
44+
res_3 = es.search(index="bank", q="Holmes", size=1, from_=1)
45+
res_4 = es.search(index="bank", q=" 39225 5686 ", size=1000, filter_path=['hits.hits._id', 'hits.hits._type'])
46+
```
47+
48+
查询指定索引的所有数据:
49+
50+
其中,index 指定索引,字符串表示一个索引;列表表示多个索引,如 `index=["bank", "banner", "country"]`;正则形式表示符合条件的多个索引,如 `index=["apple*"]`,表示以 `apple` 开头的全部索引。
51+
52+
`search` 中同样可以指定具体 `doc-type`
53+
54+
55+
```python
56+
from elasticsearch_dsl import Search
57+
58+
s = Search(using=es, index="index-test").execute()
59+
print s.to_dict()
60+
```
61+
62+
根据某个字段查询,可以多个查询条件叠加:
63+
64+
```python
65+
s = Search(using=es, index="index-test").query("match", sip="192.168.1.1")
66+
s = s.query("match", dip="192.168.1.2")
67+
s = s.excute()
68+
```
69+
70+
多字段查询:
71+
72+
```python
73+
from elasticsearch_dsl.query import MultiMatch, Match
74+
75+
multi_match = MultiMatch(query='hello', fields=['title', 'content'])
76+
s = Search(using=es, index="index-test").query(multi_match)
77+
s = s.execute()
78+
79+
print s.to_dict()
80+
```
81+
82+
还可以用 `Q()` 对象进行多字段查询,`fields` 是一个列表,`query` 为所要查询的值。
83+
84+
85+
```python
86+
from elasticsearch_dsl import Q
87+
88+
q = Q("multi_match", query="hello", fields=['title', 'content'])
89+
s = s.query(q).execute()
90+
91+
print s.to_dict()
92+
```
93+
94+
`Q()` 第一个参数是查询方法,还可以是 `bool`
95+
96+
```python
97+
98+
q = Q('bool', must=[Q('match', title='hello'), Q('match', content='world')])
99+
s = s.query(q).execute()
100+
101+
print s.to_dict()
102+
```
103+
104+
通过 `Q()` 进行组合查询,相当于上面查询的另一种写法。
105+
106+
```python
107+
q = Q("match", title='python') | Q("match", title='django')
108+
s = s.query(q).execute()
109+
print(s.to_dict())
110+
# {"bool": {"should": [...]}}
111+
112+
q = Q("match", title='python') & Q("match", title='django')
113+
s = s.query(q).execute()
114+
print(s.to_dict())
115+
# {"bool": {"must": [...]}}
116+
117+
q = ~Q("match", title="python")
118+
s = s.query(q).execute()
119+
print(s.to_dict())
120+
# {"bool": {"must_not": [...]}}
121+
```
122+
123+
过滤,在此为范围过滤,`range` 是方法,`timestamp` 是所要查询的 `field` 名字,`gte` 为大于等于,`lt` 为小于,根据需要设定即可。
124+
125+
关于 `term``match` 的区别,`term` 是精确匹配,`match` 会模糊化,会进行分词,返回匹配度分数,(`term` 如果查询小写字母的字符串,有大写会返回空即没有命中,`match` 则是不区分大小写都可以进行查询,返回结果也一样)
126+
127+
```python
128+
# 范围查询
129+
s = s.filter("range", timestamp={"gte": 0, "lt": time.time()}).query("match", country="in")
130+
# 普通过滤
131+
res_3 = s.filter("terms", balance_num=["39225", "5686"]).execute()
132+
```
133+
134+
其他写法:
135+
136+
```python
137+
s = Search()
138+
s = s.filter('terms', tags=['search', 'python'])
139+
print(s.to_dict())
140+
# {'query': {'bool': {'filter': [{'terms': {'tags': ['search', 'python']}}]}}}
141+
142+
s = s.query('bool', filter=[Q('terms', tags=['search', 'python'])])
143+
print(s.to_dict())
144+
# {'query': {'bool': {'filter': [{'terms': {'tags': ['search', 'python']}}]}}}
145+
s = s.exclude('terms', tags=['search', 'python'])
146+
# 或者
147+
s = s.query('bool', filter=[~Q('terms', tags=['search', 'python'])])
148+
print(s.to_dict())
149+
# {'query': {'bool': {'filter': [{'bool': {'must_not': [{'terms': {'tags': ['search', 'python']}}]}}]}}}
150+
```
151+
152+
聚合可以放在查询,过滤等操作的后面叠加,需要加 `aggs`
153+
154+
`bucket` 即为分组,其中第一个参数是分组的名字,自己指定即可,第二个参数是方法,第三个是指定的 `field`
155+
156+
`metric` 也是同样,`metric` 的方法有 `sum``avg``max``min` 等,但是需要指出的是,有两个方法可以一次性返回这些值,`stats``extended_stats`,后者还可以返回方差等值。
157+
158+
```python
159+
# 实例1
160+
s.aggs.bucket("per_country", "terms", field="timestamp").metric("sum_click", "stats", field="click").metric("sum_request", "stats", field="request")
161+
162+
# 实例2
163+
s.aggs.bucket("per_age", "terms", field="click.keyword").metric("sum_click", "stats", field="click")
164+
165+
# 实例3
166+
s.aggs.metric("sum_age", "extended_stats", field="impression")
167+
168+
# 实例4
169+
s.aggs.bucket("per_age", "terms", field="country.keyword")
170+
171+
# 实例5,此聚合是根据区间进行聚合
172+
a = A("range", field="account_number", ranges=[{"to": 10}, {"from": 11, "to": 21}])
173+
174+
res = s.execute()
175+
```
176+
最后依然要执行 `execute()`,此处需要注意,`s.aggs` 操作不能用变量接收(如 `res=s.aggs`,这个操作是错误的),聚合的结果会保存到 `res` 中显示。
177+
178+
179+
排序
180+
```python
181+
s = Search().sort(
182+
'category',
183+
'-title',
184+
{"lines" : {"order" : "asc", "mode" : "avg"}}
185+
)
186+
```
187+
188+
分页
189+
```python
190+
s = s[10:20]
191+
# {"from": 10, "size": 10}
192+
```
193+
194+
一些扩展方法,感兴趣的同学可以看看:
195+
196+
```python
197+
s = Search()
198+
199+
# 设置扩展属性使用`.extra()`方法
200+
s = s.extra(explain=True)
201+
202+
# 设置参数使用`.params()`
203+
s = s.params(search_type="count")
204+
205+
# 如要要限制返回字段,可以使用`source()`方法
206+
# only return the selected fields
207+
s = s.source(['title', 'body'])
208+
# don't return any fields, just the metadata
209+
s = s.source(False)
210+
# explicitly include/exclude fields
211+
s = s.source(include=["title"], exclude=["user.*"])
212+
# reset the field selection
213+
s = s.source(None)
214+
215+
# 使用dict序列化一个查询
216+
s = Search.from_dict({"query": {"match": {"title": "python"}}})
217+
218+
# 修改已经存在的查询
219+
s.update_from_dict({"query": {"match": {"title": "python"}}, "size": 42})
220+
```
221+
222+
参考文档:
223+
224+
http://fingerchou.com/2017/08/12/elasticsearch-dsl-with-python-usage-1/
225+
226+
http://fingerchou.com/2017/08/13/elasticsearch-dsl-with-python-usage-2/
227+
228+
https://blog.csdn.net/JunFeng666/article/details/78251788

哈夫曼树和哈夫曼编码.md

+126
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
关于哈夫曼树的定义、构建以及哈夫曼编码,可以参考《大话数据结构》这本书,也可以看这篇博客( https://www.cnblogs.com/kubixuesheng/p/4397798.html ),写的也很清楚。
2+
3+
下面主要来看一下哈夫曼树的 Python 实现:
4+
5+
```python
6+
#!/usr/bin/env python
7+
# -*- coding: utf-8 -*-
8+
9+
10+
# 统计字符出现频率,生成映射表
11+
def count_frequency(text):
12+
chars = []
13+
ret = []
14+
15+
for char in text:
16+
if char in chars:
17+
continue
18+
else:
19+
chars.append(char)
20+
ret.append((char, text.count(char)))
21+
22+
return ret
23+
24+
25+
# 节点类
26+
class Node:
27+
def __init__(self, frequency):
28+
self.left = None
29+
self.right = None
30+
self.father = None
31+
self.frequency = frequency
32+
33+
def is_left(self):
34+
return self.father.left == self
35+
36+
37+
# 创建叶子节点
38+
def create_nodes(frequency_list):
39+
return [Node(frequency) for frequency in frequency_list]
40+
41+
42+
# 创建Huffman树
43+
def create_huffman_tree(nodes):
44+
queue = nodes[:]
45+
46+
while len(queue) > 1:
47+
queue.sort(key=lambda item: item.frequency)
48+
node_left = queue.pop(0)
49+
node_right = queue.pop(0)
50+
node_father = Node(node_left.frequency + node_right.frequency)
51+
node_father.left = node_left
52+
node_father.right = node_right
53+
node_left.father = node_father
54+
node_right.father = node_father
55+
queue.append(node_father)
56+
57+
queue[0].father = None
58+
return queue[0]
59+
60+
61+
# Huffman编码
62+
def huffman_encoding(nodes, root):
63+
huffman_code = [''] * len(nodes)
64+
65+
for i in range(len(nodes)):
66+
node = nodes[i]
67+
while node != root:
68+
if node.is_left():
69+
huffman_code[i] = '0' + huffman_code[i]
70+
else:
71+
huffman_code[i] = '1' + huffman_code[i]
72+
node = node.father
73+
74+
return huffman_code
75+
76+
77+
# 编码整个字符串
78+
def encode_str(text, char_frequency, codes):
79+
ret = ''
80+
for char in text:
81+
i = 0
82+
for item in char_frequency:
83+
if char == item[0]:
84+
ret += codes[i]
85+
i += 1
86+
87+
return ret
88+
89+
90+
# 解码整个字符串
91+
def decode_str(huffman_str, char_frequency, codes):
92+
ret = ''
93+
while huffman_str != '':
94+
i = 0
95+
for item in codes:
96+
if item in huffman_str and huffman_str.index(item) == 0:
97+
ret += char_frequency[i][0]
98+
huffman_str = huffman_str[len(item):]
99+
i += 1
100+
101+
return ret
102+
103+
104+
if __name__ == '__main__':
105+
text = raw_input('The text to encode:')
106+
107+
char_frequency = count_frequency(text)
108+
nodes = create_nodes([item[1] for item in char_frequency])
109+
root = create_huffman_tree(nodes)
110+
codes = huffman_encoding(nodes, root)
111+
112+
huffman_str = encode_str(text, char_frequency, codes)
113+
origin_str = decode_str(huffman_str, char_frequency, codes)
114+
115+
print 'Encode result:' + huffman_str
116+
print 'Decode result:' + origin_str
117+
```
118+
119+
120+
参考文档:
121+
122+
https://www.cnblogs.com/tomhawk/p/7471133.html
123+
124+
https://gist.github.com/Jackeriss/268074dbd383a9eabb7fac1d50ed98e5
125+
126+
https://arianx.me/2018/06/24/Python-Huffman-Tree/

0 commit comments

Comments
 (0)