全文检索

全文检索是将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。
这部分从非结构化数据中提取出然后重新组织的信息,我们称之索引。这种先建立索引,再对索引进行搜索的过程就叫全文检索(Full-text Search)。

Lucene是apache下的一个开源的全文检索引擎工具包(类库)。它的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。Lucene提供了完整的查询引擎和索引引擎,部分文本分析引擎。

更新依据的字段只能是字符串类型,StringField。

Document doc=new Document();
doc.add(new StringField("id","abcd",Field.Store.YES));
indexWriter.updateDocument(new Term("id","abcd"),doc);

Field.Store.YES或者NO是用来决定分词前的原内容是否存储。

lucene一个field多个条件查询
https://blog.csdn.net/guiyecheng/article/details/56484049

用lucene实现在一个(或者多个)字段中查找多个关键字
https://www.cnblogs.com/xudong-bupt/archive/2013/05/08/3065297.html

Elastic Search 概述(一)
https://blog.csdn.net/yezonggang/article/details/80064394

Elasticsearch的不足
http://dockone.io/article/3655

MongoDB

mongodb命令行group分组和java代码中group分组
https://www.2cto.com/database/201607/528258.html
MongoDB Counting and Grouping
http://wiki.summercode.com/mongodb_aggregation_functions_and_ruby_counting_and_grouping
mongodb和spring集成中MongoTemplate的总结是使用方法
http://blog.csdn.net/ruishenh/article/details/12842331
MongoTemplate:增加数据。根据id查询,条件查询,聚合group 和 distinct
http://147175882.iteye.com/blog/1565378
Spring Data JPA – Reference Documentation
https://docs.spring.io/spring-data/jpa/docs/1.8.0.M1/reference/html/#repositories.query-methods.query-creation
Spring Data for Mongo 介绍
http://colobu.com/2014/12/03/Spring-Data-for-Mongo-Introduction/

MongoDB文档

https://docs.mongodb.com/
https://docs.mongodb.com/manual/
https://docs.mongodb.com/manual/crud/
MongoDB教程
http://www.yiibai.com/mongodb/mongodb_indexing.html
MongoDB 基础知识
https://segmentfault.com/a/1190000002694268?_ea=184402
Mongoose学习参考文档——基础篇
http://ourjs.com/detail/53ad24edb984bb4659000013
Spring Boot中使用MongoDB数据库
http://www.tuicool.com/articles/QjmIFnf
MongoDB学习笔记—Linux下搭建MongoDB环境
http://www.cnblogs.com/hanyinglong/archive/2016/07/21/5690611.html
Install MongoDB Community Edition on OS X
https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/
MongoDB Tutorial
https://www.tutorialspoint.com/mongodb/index.htm

MongoDB将信息存储在BSON(Binary JSON)中,对海量数据存储有着很明显的优势。并且当需要一个无模式或模式灵活的数据结构时,MongoDB是一个不错的选择。MongoDB对数据结构的更改相对轻松和宽容,这是NoSQL解决方案的卖点。在MySQL世界中有许多改进使在线模式更改成为可能,只创建记录而不定义结构增加了MongoDB的灵活性。
选择MongoDB的另一个原因是它具有设置复制环境,内置分片和自动选择方面的功能。在MongoDB中设置复制环境很容易,自动选择过程允许从数据库在主数据库故障的情况下接管。内置分片允许简单的横向扩展。在MySQL环境中管理,设置和配置会很复杂。
MongoDB缺点:主要是无事物机制!

MySQL与MongoDB的操作对比
http://blog.csdn.net/suxinpingtao51/article/details/40981621
对比MySQL,你究竟在什么时候更需要MongoDB
http://www.csdn.net/article/2014-03-06/2818652-when-use-mongodb-rather-mysql

安装mongodb

https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/
https://docs.mongodb.com/manual/tutorial/install-mongodb-enterprise-on-ubuntu/

MongoDB是免费的,有Enterprise和Community两个版本,在文档中可以看到差异主要体现在安全认证、系统认证等方面。

## Enterprise-Only Options:
#auditLog:
#snmp:

http://www.178linux.com/13492

修改端口等配置

vi /etc/mongod.conf
#修改端口和监听IP
# network interfaces
net:
  port: 27017
  #bindIp: 127.0.0.1
  #允许本机所有ip
  bindIp: 0.0.0.0

在ubuntu16.04中设置开机启动mongodb服务
sudo systemctl enable mongod
https://www.cnblogs.com/weschen/p/7395667.html

常用查询

./mongod -version
mongo #默认参数为 localhost:27017
mongo localhost:14000
help
show dbs
use dbname1
db.auth('username','password');
show collections
db.collectionName1.find()
#查看索引
db.collectionName1.getIndexes()
#查看版本
db.version()
#创建索引
db.collectionName1.ensureIndex({"_id":1})

常用修改

db.collectionName1.update({"_id" : ObjectId("58d0f91a7e113c661b0fc997")},{$set:{"code":"11112222"}})
db.collectionName1.insert({"name" : "abc","alias" : "123"})
#修改字段名
db.collectionName1.update({}, {$rename : {"oldColumnName" : "newColumnName"}}, false, true)

mongo3.0备份还原数据

#备份
~/mongodb/bin/mongodump -h localhost:27017 -d my_db -o ./
#还原
~/mongodb/bin/mongorestore -h localhost:27017 -d my_db ~/mongo-db/20170705/my_db --drop

mongoDB 2.0 文件目录

配置文件   /etc/mongod.conf 
数据库日志 /var/log/mongodb
数据库文件 /var/lib/mongodb
#关闭和启动数据库服务
sudo service mongod stop
sudo service mongod start

日志中:”nscanned” 表示查询了多少个文档。

MongoDB学习笔记(索引)
http://www.cnblogs.com/stephen-liu74/archive/2012/08/01/2561557.html

手动启动Mongo

cd  ~/mongodb/bin/
./mongod -dbpath=../data -logpath=../log/mongodb.log --logappend&
~/mongodb/bin/mongod -config  ~/mongodb/etc/mongodb.conf
./mongod -config ../etc/mongodb.conf --fork
#mongodb config file
dbpath=../data/db
logpath=../mongodb.log
logappend = true
port = 14000
fork = false
httpinterface=true

关闭数据库

# mongo localhost:27017
> use admin
> db.shutdownServer()

查询示例:

操作语句
修改多行
db.getCollection('operateRecord').update({"operateType":"门禁控制"},{"$set":{"operateType":"door"}},{multi: true})
删除列
db.User.update({},{$unset:{'operateTypel':''}},false, true)

常用查询 
db.getCollection('devices').find({name:/^mic/}).sort({display_name:1})
db.getCollection('devices').find({name:/^mic/,display_name:/^圆桌/},{_id:1}).sort({mic_router_id:1,name:1})
db.getCollection('devices').find({name:/^mic/,display_name:/^二层/},{_id:1}).sort({mic_router_id:1,name:1})
db.getCollection('alarmRecord').find({stateTime:{'$lt':new Date('2017/03/15')}}).count()
db.getCollection('alarmRecord').remove({stateTime:{'$lt':new Date('2017/03/16')}})
db.getCollection('devicegroups').find({tags:[‘aaaa’]})  数组中查找
db.getCollection('devices').find({name:/^decoder/}) 所有网络音频编解码器
db.getCollection('devices').find({device_type:ObjectId("585601376868180438aea058")})   所有门禁
db.getCollection('devices').find({device_type:ObjectId("59015c66dece7169709a02f4"))}) 所有安防摄像头
db.getCollection('devices').find({name:{$in:["door_2_40","door_2_41"]}})
db.Alert.find({collectorId:{$exists:true}})
#查询字段存在
db.getCollection('Unit').find({parametervalue:{$exists:true}},{}).sort({_id:-1})

添加
db.UnitType.insert({"name" : "CarelPJ0003","alias" : "qhtf-PJ0003"})

修改
db.UnitType.update({"_id" : ObjectId("583cca533b5e105d024c79f7")},{$set:{"name":"YIDE-HP 020"}})
db.UnitType.update({"_id" : ObjectId("599a3e7e80577cc54e0f4eb4")},{$unset:{"template":"lsqk-1"}})
db.Alert.update({collectorId:{$exists:true}},{$set:{"unitId":ObjectId("000000000000000000000000")}},false,true)

统计分路器个数
db.getCollection('devices').group({
    key: {mic_router_id: 1},
    cond: {name:/^mic/},
    reduce: function (curr, result) {
        result.count++;
    },
    initial: {
        count: 0
    }
});

按类型列出设备 //http://www.xker.com/page/e2015/07/205772.html
db.getCollection('devices').group({
    key: {device_type: 1},
    reduce: function (curr, result) {
        result.count++;
        result.ids.push(curr._id);
    },
    initial: {
        count: 0,
        ids:[]
    }
});

Lookup多表关联处理
db.getCollection('devicetypes').aggregate([{$lookup:{from: "devices", localField:"_id", foreignField: "device_type", as: "devices"}}
,{$project:{_id:1,name:1,devices:1}}
,{$group: {_id: "$_id", deviceTypeName: {$first:"$name"}, deviceIds:{$push:"$devices._id"}, count:{$sum: 1} }}
])
或者
db.getCollection('devices').aggregate([{$lookup:{from: "devicetypes", localField:"device_type", foreignField: "_id", as: "deviceType"}}
,{$group: {_id:{_id:"$deviceType._id", display_name:"$deviceType.display_name", name:"$deviceType.name"}, deviceIds:{$push:"$_id"}, count:{$sum: 1} }}
])
或者
db.getCollection('devices').aggregate([{$lookup:{from: "devicetypes", localField:"device_type", foreignField: "_id", as: "deviceType"}}
,{$group: {_id:"$deviceType._id", display_name:{$first:"$deviceType.display_name"}, name:{$first:"$deviceType.name"}, deviceIds:{$push:"$_id"}, count:{$sum: 1} }}
])

各个机组的最新的监测记录 https://docs.mongodb.com/manual/reference/operator/aggregation/max/
db.getCollection('RealtimeLog').aggregate(
   [
        {$match: {"unitId": {"$in":[ObjectId("596dac89c13a10339936610b")]}}},
     {
       $group:
         {
           _id: "$unitId",
          maxId: { $max: "$_id" }
         }
     }
   ]
)

统计各个unitId的条数
db.getCollection('Alert').aggregate([{$group : {_id : "$unitId", num_tutorial : {$sum : 1}}}])

forEach示例
db.CollectorGarbage.find({address:/中间的文字/}).forEach(function(doc) {
  doc._id=doc.code;
  doc.code=null;
  db.Collector.insert(doc);
});

db.devices.find({name:/^micRouter/}).forEach(function(doc) {
  var singles=[2,5,12,14,16,18,20,25,28,31,34];
  var number=doc.name.replace("micRouter","");
  var single=false;
  var n=parseInt(doc.number);
  if(singles.indexOf(n)>=0){
    single=true;
  }
  db.devices.update({"_id" : doc._id},{$set:{"single":single,"number": NumberInt(number)}})
});

db.devices.find({name:/^micRouter/}).sort({number:1}).forEach(function(doc) {
  var micCode= parseInt(doc.number * 4 - 3 + 10000);
  var newdoc={
      "device_type" : ObjectId("583cf97345fa750587159ce7"),
      "mic_router_id" : ""+doc.number,
      "name" : "mic"+micCode,
      "remote_id" : ""+micCode
  };
  db.devices.insert(newdoc);

  if(!doc.single){
  micCode+=2;
  var newdoc={
    "device_type" : ObjectId("583cf97345fa750587159ce7"),
    "mic_router_id" : ""+doc.number,
    "name" : "mic"+micCode,
    "remote_id" : ""+micCode
  };
  db.devices.insert(newdoc);
  }
});

db.devices.find({device_type:ObjectId("583cf97345fa750587159ce7")}).forEach(
   function(item){                 
       db.devices.update({"_id":item._id},{"$set":{"display_name":"话筒"+item.display_name.replace("mic","")}},false,true) 
    }
)

数据库加密码

use admin
db.auth("userForAdmin","passForAdmin");
#use 即可新建数据库
use newdb1
db.createUser({user: "userForNewDB1", pwd: "123456", roles: [{ role: "dbOwner", db: "newdb1" }]})

distinct

distinct 以数组的形式返回集合中指定字段的不重复值
db.collection_name.distinct(field,query,options)
field -----指定要返回的字段(string)
query-----条件查询(document)
options-----其他的选项(document)

数据库性能优化

1.全表连接变为,先约束为小表再连接。

2.随着集合的增长,需要针对查询条件中数据量大的排序字段做索引。
如果没有对索引的键排序,数据库需要将所有数据提取到内存并排序。因此在做无索引排序时,如果数据量过大以致无法在内存中进行排序,数据库将会报错。初步可以对出现查询慢的表建立索引、组合索引。

3.MySQL数据库的读写分离:分库、分表、分读写 (dataguard 备库)
http://blog.csdn.net/kobejayandy/article/details/8775255
http://blog.csdn.net/kobejayandy/article/details/8775138
参考
https://www.cnblogs.com/panxuejun/p/5887118.html
https://www.jianshu.com/p/65e8a31fbab8
https://www.cnblogs.com/alvin_xp/p/4162249.html

MySQL数据库则可以利用MySQL主从配置,实现读写分离,既起到备份作用又可以减轻数据库的读写的压力。读写分离的基本原理是让“主”数据库处理事务性增、改、删操作,“从”数据库处理查询操作。利用数据库复制把事务性操作导致的变更从主数据库同步到从数据库。写库有一个,读库可以有多个,采用日志同步的方式实现主库和多个读库的数据同步。

Mysql 的 Replication 是一个异步的复制过程,从一个MySQL节点(称为Master)复制到另一个MySQL节点(称Slave)。在 Master 与 Slave 之间的实现整个复制过程主要由三个线程来完成,其中两个线程(SQL 线程和 I/O 线程)在 Slave 端,另外一个线程(I/O 线程)在 Master 端。
要实现 MySQL 的 Replication ,首先要打开 Master 端的 Binary Log,整个复制过程实际上就是 Slave 从 Master 端获取日志,然后在自己身上完全顺序的执行日志中所记录的各种操作。
MySQL的Replication原理有以下结论和推论:
* 每个从仅可以设置一个主。
* 主在执行sql之后,记录二进制log文件(bin-log)。
* 从连接主,并从主获取bin-log,存于本地relay-log,并从上次记住的位置起执行sql,一旦遇到错误则停止同步。
* 主从间的数据库不是实时同步。
* 如果主从的网络断开,从会在网络正常后,批量同步。
* 如果对从进行修改数据,那么很可能从在执行主的bin-log时出现错误而停止同步,这个是很危险的操作。所以一般情况下,非常小心的修改从上的数据。
* 一个衍生的配置是双主,互为主从配置,只要双方的修改不冲突,可以工作良好。
* 如果需要多主的话,可以用环形配置,这样任意一个节点的修改都可以同步到所有节点。

4.数据缓存
大型网站为了应对大量的并发访问,除了在业务端实现分布式负载均衡,还要减少数据库的连接,例如采用优秀的代码框架进行代码优化,采用优秀的数据缓存技术如memcached,如果资金丰厚还可以架设服务器群来分担主数据库的压力。

Mysql

删除重复记录

删除重复记录个数是2的:

delete list_table from list_table,(select max(id) as id from list_table group by href having count(*)>1) as t2 where list_table.id=t2.id

去掉字段中的换行,制表符

\n也可以是用char(10)代替,\r可以用char(13)代替

update list_table set briefDesc = replace(briefDesc ,"\r\n","")
update list_table set briefDesc = replace(briefDesc ,"\t","")
UPDATE list_table SET briefDesc = REPLACE(REPLACE(briefDesc, CHAR(10), ''), CHAR(13),'')

重置auto_increment字段的起始值

有些表只用来统计,其id不会作为外键,所以可以自由修改它的id。
通过命令ALTER TABLE share_table AUTO_INCREMENT=605 或通过phpMyAdmin操作表选项修改,都不成功。
后来先去掉id字段的auto_increment属性,再添加上它,就会自动从最大的id开始了。

用选择的数据创建临时表

创建临时表可以简化一些复杂的sql语句

create table temp_table SELECT articleId,count(*) as count FROM `share_table` group by articleId
insert into temp_table SELECT articleId,count(*) as count FROM `share_table` group by articleId

联合update

UPDATE list_table A, temp_table B
SET A.shareTimes=B.count
WHERE A.id=B.articleId

Could not connect: Access denied for user ‘root’@’localhost’ (using password: YES)

修改root密码

update user set password=password('abc') where user='root'

重启mysql

查询index

 show index from list_table
 alter table drop index xxx;

表 is marked as crashed and should be repaired

在phpmyadmin中选中库再在表的列表中选择对应表名,再选择选中项中的修复表,执行修复。可能会遇到需要修改表文件的组和拥有者。

修改数据库密码

进入mysql库

UPDATE user SET password=PASSWORD('123456') WHERE user='root'

Linux环境下修改MySQL端口

vi /alidata/server/mysql/my.cnf
修改port=3306
service mysql restart

授权访问者

#命令行登录
本地:mysql -uroot -p 
本地:mysql -u root -p, 回车后输入密码; 也可以p后不加空格,直接加密码,回车就登录了。
远程:mysql -hxx.xx.xx.xx -P 3306 -u -pxxx

#授权允许从ip为192.168.1.6的主机以root用户和password1作为密码,连接到mysql服务器。
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.6' IDENTIFIED BY 'password1' WITH GRANT OPTION;
#修改生效并退出
FLUSH PRIVILEGES
EXIT

修改字段部分内容

update `list_table_test` set `thumbnailUrl`=concat('http://pic.cnblogs.com',substr(`thumbnailUrl`,18)) WHERE `thumbnailUrl` like 'http://www.cnblogs.com/pic.cnblogs.com/face/%'

SELECT replace(replace(href,'http://so.brogrammer.org/view_',''),'.aspx','') FROM `poetry_table` WHERE href like 'http://so.brogrammer.org/view_%'

工具

Navicat

时序数据库

influxdb

measurement和tags共同称为key,如果在tag value中的空格,应以“\”加上空格表示。
tag中的值必须是string类型,其实是起到索引的作用。

field中的值可以为Integer、float、Boolean、string类型。若为Integer类型,则值后必须加“i”,否则该值为float类型,Boolean类型的值的表示方式有很多,直接写成:t、T、true、TRUE, 和 f、F、false、FALSE。
插入数据时,时间戳部分如果被省略,则默认将当前时间的时间戳插入数据库,否则按照用户输入的时间戳插入。

influxDB属于时序数据库,没有提供修改和删除数据的方法。但是删除可以通过InfluxDB的数据保存策略(Retention Policies)来实现。
测试发现,重写同一条记录可覆盖上一条记录,可以做到修改这条记录。
另外分析,从系统整体上来看,updateTime并没有使用到,因为实时数据并不再从数据库中查询获得,而是使用内存中的最新采集数据。查询统计时使用的时间是createTime。
如果不记录updateTime,并且如果最新采集数据一直没有特征变化,最终数据库中存储的可能是较早期采集插入的数据。
如果不记录updateTime,并且如果要存储最后一次采集时间,可额外记录。一般情况下,当前时间即是最新一条记录的修改时间,下一条数据的创建时间减去采集周期是上一条数据的最后修改时间。

wget https://dl.influxdata.com/influxdb/releases/influxdb-1.5.2.x86_64.rpm
sudo yum localinstall influxdb-1.5.2.x86_64.rpm
service influxdb start

#命令行连接
influx -precision rfc3339
drop database mydb1
CREATE DATABASE mydb1
SHOW DATABASES 
USE mydb1
SHOW MEASUREMENTS
drop measurement measurement1

#增加数据采用insert的方式,表名与数据之间用逗号(,)分隔,tag和field之间用 空格分隔,多个tag或者多个field之间用逗号(,)分隔。
INSERT measurement1,field1=serverA,field1=us_west field3=0.64

select * from "measurement1"
select * from measurement1 limit 1
select * from "measurement1" where "value">0.9  

#series表示表里面的数据,series主要通过tags排列组合算出来。
show series from measurement1

InfluxDB简明手册
https://legacy.gitbook.com/book/xtutu/influxdb-handbook/details

使用influxdb和grafana快速开发监控系统
http://0x0010.com/2017/07/monitor-system-based-on-influxdb-grafana/
https://github.com/miwurster/spring-data-influxdb
https://docs.influxdata.com/influxdb/v1.5/guides/writing_data/
https://docs.influxdata.com/influxdb/v1.5/tools/api_client_libraries/
一篇文章告诉你,为什么时序数据库会成为新趋势?
http://www.tuicool.com/articles/r6R3aaY
http://flacro.me/influxdb/
Grafana的安装(CentOS )- 千月带你美化监控数据 grafana(1)
https://blog.csdn.net/syshzbtt/article/details/71574204
### NOT starting grafana-server by default on bootup, please execute
sudo /sbin/chkconfig –add grafana-server
### In order to start grafana-server, execute
sudo service grafana-server start

InfluxDB系列学习教程目录
https://www.linuxdaxue.com/influxdb-study-series-manual.html
使用 InfluxDB 有感
https://toutiao.io/posts/viqzdg/preview
https://www.jianshu.com/p/d71646c08317
https://www.jianshu.com/p/a1344ca86e9b