Diretório de artigos
- documentos de referência
- Índice
- Experimento 1: juntar e filtrar
- Experimento 2: Agregados
- Experimento 3: HeapPage e HeapFile, bufferpool perfeito
- Experimento 4: Inserção e exclusão
- Experimento 5: Estratégia de Eliminação
- Experimento 6: consulta de junção e filtro
- Experimento 7: uso do analisador de consulta
- pergunta
- Resumir
documentos de referência
Índice
- filtrar, juntar, ordenar por
- função agregada
- Inserção e exclusão de tupla
- Despejo de substituição de página
Experimento 1: juntar e filtrar
predicado :
Três domínios:
- arquivado: o id do domínio
- op: operador
- operando: operando
Implementação da função:
- filtro()
- para sequenciar()
public boolean filter(Tuple t) {
// some code goes here
return t.getField(this.field).compare(op, this.operand); // 这个compare已经由某一个域给定义好了int和string的比较规则
}
joinpredict
- Comparação de campos em duas tuplas para operação de junção
área:
- campo de duas tuplas
- operador
função
- filtro()
public boolean filter(Tuple t1, Tuple t2) {
// some code goes here
return t1.getField(this.field_a).compare(op, t2.getField(this.field_b));
}
filtro
- Execute a operação do filtro
- super.close() e open()
- buscarNext()
protected Tuple fetchNext() throws NoSuchElementException,
TransactionAbortedException, DbException {
// some code goes here
while(child.hasNext()) {
Tuple tuple = child.next();
if (this.p.filter(tuple)) // 通过过滤器看看是否满足条件
return tuple;
}
return null;
}
juntar
área:
- private final JoinPredicate joinPredicate; comparação de tupla dupla
- private OpIterator child1; iterador de tupla 1
- private OpIterator filho2; iterador de tupla 2
- private Tuple t; Tupla temporária, salva a Tupla de child1 usada na última iteração
Isso é usado principalmente para continuar a usar a tupla atual durante a próxima passagem, porque pode haver vários resultados elegíveis, ou seja, um para muitos, então t1 não pode pular diretamente para o próximo e usar um valor temporário para salvar a tupla atual.
função:
- buscarNext()
protected Tuple fetchNext() throws TransactionAbortedException, DbException {
// some code goes here
// t 的意义就是 笛卡尔积, 一个可能对多个相等
while (child1.hasNext() || t != null){
if(child1.hasNext() && t == null){
t = child1.next();
}
while(child2.hasNext()){
Tuple t2 = child2.next();
if(joinPredicate.filter(t, t2)){
TupleDesc td1 = t.getTupleDesc();
TupleDesc td2 = t2.getTupleDesc();
// 合并
TupleDesc tupleDesc = TupleDesc.merge(td1, td2);
Tuple newTuple = new Tuple(tupleDesc);
// 设置路径, 暂时不先设置
// newTuple.setRecordId(t.getRecordId());
int i = 0;
for (; i < td1.numFields(); i++) {
newTuple.setField(i, t.getField(i));
}
for (int j = 0; j < td2.numFields(); j++) {
newTuple.setField(i + j, t2.getField(j));
}
// 遍历完,t2重头,t走向下一个
if(!child2.hasNext()){
child2.rewind();
t = null;
}
return newTuple;
}
}
// 重置 child2
child2.rewind();
t = null;
}
return null;
}
Experimento 2: Agregados
Agregador
área
-
filho: iterador de tabela
-
afield: o id do domínio que precisa ser agregado
-
gfield: o id do campo que precisa ser agrupado
-
gfieldType: O tipo de campo que precisa ser agrupado, pois não há informação na tabela, só pode ser passado pela classe pai.
-
AggHandler: Um manipulador personalizado usado para implementar diferentes funções de agregação. Cabe ao operador decidir que tipo de função agregada criar.
-
- Salve o mapa de resposta {chave: agrupamento, valor: o resultado de cada grupo de funções de agregação}
- O método handle, um método abstrato, implementa lógica de função agregada específica.
método
-
mergeTotuple: atualize o conjunto de resultados no manipulador por meio de um manipulador personalizado.
-
iterator: Iterator, que converte o conjunto de resultados em forma de tupla. Em seguida, retorna um iterador sobre a lista de tuplas.
-
- O cabeçalho da tupla é {groupVal, aggVal}
- O conteúdo da tupla é o par chave-valor no mapa
o código
public OpIterator iterator() {
// some code goes here
// throw new
// UnsupportedOperationException("please implement me for lab2");
Map<Field, IntField> ans = handler.ans;
List<Tuple>tuples = new ArrayList<>();
TupleDesc tupleDesc; // 创建迭代器的时候,需要用到
if (gfield == NO_GROUPING) {
// 如果没有group
// 创建tuple
tupleDesc = new TupleDesc(new Type[]{
Type.INT_TYPE}, new String[]{
"aggregateVal"});
Tuple tuple = new Tuple(tupleDesc);
// 把查询到的结果放入tuple中
tuple.setField(0, ans.get(null));
// 不要忘了把创建的tuple放入到结果集中
tuples.add(tuple);
}
else {
// 如果含有group
tupleDesc = new TupleDesc(new Type[]{
this.gfieldtype, Type.INT_TYPE}, new String[]{
"groupVal", "aggregateVal"});
for (Map.Entry<Field, IntField> entry : ans.entrySet()) {
Tuple tuple = new Tuple(tupleDesc);
tuple.setField(0, entry.getKey());
tuple.setField(1, entry.getValue());
tuples.add(tuple);
}
}
return new TupleIterator(tupleDesc, tuples);
}
public void mergeTupleIntoGroup(Tuple tup) {
// some code goes here
// 获取对应域的值
IntField afield = (IntField) tup.getField(this.afield);
Field gfield = this.gfield == NO_GROUPING ? null : tup.getField(this.gfield);
handler.handle(gfield, afield);
}
private abstract class AggHandler {
private Map<Field, IntField>ans;
abstract void handle(Field gfield, IntField afield); // group by不知道什么类型,但是聚集函数得到的结果一定是int
public AggHandler() {
ans = new HashMap<>();
}
public Map<Field, IntField> getAns() {
return this.ans;
}
}
private class MinHandler extends AggHandler {
@Override
void handle(Field gfield, IntField afield) {
int x = afield.getValue();
Map<Field, IntField>ans = this.getAns();
if (ans.containsKey(gfield)) {
ans.put(gfield, new IntField(Math.min(x, ans.get(gfield).getValue())));
}
else ans.put(gfield, new IntField(x));
}
}
public IntegerAggregator(int gbfield, Type gbfieldtype, int afield, Op what) {
// some code goes here
this.gfield = gbfield;
this.afield = afield;
this.gfieldtype = gbfieldtype;
this.op = what;
switch (what) {
case MIN:
this.handler = new MinHandler(); break;
case AVG:
this.handler = new AvgHandler(); break;
case SUM:
this.handler = new SumHandler(); break;
case COUNT:
this.handler = new CountHandler(); break;
case MAX:
this.handler = new MaxHandler(); break;
default:
throw new IllegalArgumentException("聚合器不支持当前运算符");
}
}
Agregados
área:
- filho: entrada do iterador de tabela
- afield: id de campo agregado
- gfield: ID do campo do grupo
- aop: o id da função agregada
- agregador: Agregador, um dos acima, cujo tipo é determinado por um campo
- iterador: o iterador do conjunto de resultados
método:
- Construtor
- getTupleDesc(): Retorna um cabeçalho na forma de max(score). Se existe um campo para determinar o número de colunas
código:
public TupleDesc getTupleDesc() {
// some code goes here
// String afiledName = this.aop.name() + "(" + this.aggregateFieldName() + ")"; // max(id);
// Type aType = this.child.getTupleDesc().getFieldType(this.afield);
// if (this.groupFieldName() != null) {
// String gfiledName = this.groupFieldName();
// Type gType = this.child.getTupleDesc().getFieldType(this.gfield);
// return new TupleDesc(new Type[]{gType, aType},new String[]{gfiledName, afiledName});
// }
// else {
// return new TupleDesc(new Type[]{aType}, new String[]{afiledName});
// }
List<Type>types = new ArrayList<>();
List<String>names = new ArrayList<>();
if (groupFieldName() != null) {
types.add(this.child.getTupleDesc().getFieldType(this.gfield));
names.add(groupFieldName());
}
types.add(this.child.getTupleDesc().getFieldType(this.afield));
names.add(this.aop.name() + "(" + aggregateFieldName() + ")"); // 类似于max(id), AVG(score)这种
if (this.aop.equals(Aggregator.Op.SUM_COUNT)) {
// 如果有
types.add(Type.INT_TYPE);
names.add("COUNT");
}
return new TupleDesc(types.toArray(new Type[types.size()]), names.toArray(new String[names.size()]));
}
// 这里可以使用工厂模式进行改写
public Aggregate(OpIterator child, int afield, int gfield, Aggregator.Op aop) {
// some code goes here
this.child = child;
this.afield = afield;
this.gfield = gfield;
this.aop = aop;
Type gfieldtype;
if (gfield == NO_GROUPING) gfieldtype = null;
else gfieldtype = this.child.getTupleDesc().getFieldType(this.gfield);
if (this.child.getTupleDesc().getFieldType(afield).equals(Type.STRING_TYPE))
this.aggregator = new StringAggregator(gfield, this.child.getTupleDesc().getFieldType(this.gfield), afield, aop);
else this.aggregator = new IntegerAggregator(gfield, gfieldtype, afield, aop);
// desc = this.getTupleDesc();
}
Experimento 3: HeapPage e HeapFile, bufferpool perfeito
heapPage:
Adicionar ID da transação
inserir e excluir
heapFile
inserir e excluir
buffer pool
-
rubor
-
insertTuple: Essa lógica existe no BufferPoolWriteTest, mas não é obtida do bufferpool, modifique o conteúdo do insert no teste
-
- Primeiro, insira se disponível
- Em segundo lugar, não há nada para inserir, crie uma nova página, insira o arquivo
- Finalmente, a página é buscada no cache.
-
-
- A lógica das páginas no cache é, se não for lida do arquivo, caso contrário, retornar diretamente
- Além disso, o get no cache precisa ser reconstruído, a lista duplamente vinculada, o cache está cheio e o final é eliminado.
-
-
DeleteTuple
-
A lógica no iterador deu errado
Experimento 4: Inserção e exclusão
área
- ID da transação
- iterador inserido
- tabela inserida
- resultado tupleDesc
- inserir marca
método
Apenas chame Bufferpool.insert() e delete os métodos diretamente.
Experimento 5: Estratégia de Eliminação
A lista duplamente encadeada implementa LRU.
- Coloque a página no topo sempre que usá-la.
Experimento 6: consulta de junção e filtro
- Criar um arquivo
- Coloque o conteúdo, preste atenção nas quebras de linha
- executar arquivo de teste
Experimento 7: uso do analisador de consulta
- Criar um arquivo
- Execute a conversão do comando, desde que o ant seja compilado através
- Finalmente execute o comando e entre na linha de comando
- Insira uma consulta e obtenha resultados.
pergunta
-
Por que o recordId é definido como t1 após a conexão Join?
-
- deve ser definido como uma tabela temporária
- mas sem tabela temporária
-
Por que herdar de Operator em vez de Implement OpIterator
-
- Porque next e hasNext() são métodos duplicados
-
Por que abrir e fechar precisam de super.open e super.close?
-
- Porque esses dois métodos são substituídos na classe pai. A lógica de julgamento está em hasNext() e next() da classe pai
- Portanto, devemos primeiro alterar o estado da classe pai, para passar os dois métodos acima e, em seguida, modificar nosso próprio método.
-
Qual deve ser o recordId ao criar uma nova tupla?
-
Qual é o objetivo de definircrianças?
-
Como sum_count é implementado? Além disso, por que sum_count precisa adicionar uma nova coluna em desc?
-
- Por causa das duas operações, uma nova coluna é adicionada.
-
Ao inserir e excluir tuplas, o arquivo deve ser gravado imediatamente? Se não, quando o arquivo será gravado?
-
Por que marcar escrita suja no bufferpool? Não está jogando quando DbFile?
-
Ao final da eliminação, preciso atualizar o disco? flush e delete são duas operações. Essas duas operações são controladas por camadas superiores. Se você precisar liberar o disco imediatamente, delete(), flush, caso contrário, não precisará.
-
A lógica no iterador deve ser que não há ninguém nesta página, encontre o primeiro e termine se não houver nenhum.
11. Problemas de codificação
Modifique a cópia na compilação da seguinte maneira
target name="compile" description="Compile code">
<javac srcdir="${src}/java" destdir="${build.src}" debug="on" deprecation="on" optimize="off" includes="**">
<!--给编译器指定编码,防止出现:"警告: 编码 GBK 的不可映射字符"-->
<compilerarg line="-encoding UTF-8 "/>
<classpath refid="classpath.base" />
</javac>
<Compile srcdir="${src}/java" destdir="${build.src}">
<classpath refid="classpath.base"/>
</Compile>
<copy todir="${build}" flatten="true">
<fileset dir="${src}">
<include name="bin/*.sh"/>
</fileset>
</copy>
</target>
Resumir
- Resumo da depuração: Devido ao problema de no_group_avg encontrado. Execute a depuração de código, atinja os pontos de extremidade no código que você escreveu e esqueça de adicionar tuplas a tuplas.
- Ao inserir e excluir, o cache deve ser atualizado no tempo. Em vez de gravar o arquivo imediatamente. Portanto, existem páginas sujas.