visilization on coauthors

This commit is contained in:
pelick
2013-04-11 19:34:36 +08:00
parent eafab5ea4b
commit 2afa94b4cd
19 changed files with 462 additions and 111 deletions
@@ -36,5 +36,5 @@
#myCarousel .img-rounded {
width: 100%;
height: 500px;
height: 480px;
}
+29 -10
View File
@@ -11,10 +11,29 @@
<script src="bootstrap/js/bootstrap.min.js"></script>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="css/index.css" rel="stylesheet" />
</head>
<body>
<s:include value="smallhead.jsp"></s:include>
<!-- 搜索框 -->
<div class="container">
<div class="tabbable"> <!-- Only required for left/right tabs -->
<ul class="nav nav-tabs">
<li class="active"><a href="#tab1" data-toggle="tab">Reseacher</a></li>
<li><a href="#tab2" data-toggle="tab">Publication</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab1">
<p>Howdy, I'm in Section 1.</p>
</div>
<div class="tab-pane" id="tab2">
<p>Howdy, I'm in Section 2.</p>
</div>
</div>
</div>
</div>
<div class="container" id="home_container">
<div id="myCarousel" class="carousel slide">
<ol class="carousel-indicators">
@@ -28,26 +47,26 @@
<img src="images/logo/mongodb.png" class="img-rounded">
<div class="carousel-caption">
<h4>Mongodb</h4>
<p class="lead">
<p>
MongoDB is a NoSQL...
</p>
</div>
</div>
<div class="item">
<img src="images/logo/solr.png" class="img-rounded">
<img src="images/logo/jquery.png" class="img-rounded">
<div class="carousel-caption">
<h4>Solr</h4>
<h4>jQuery</h4>
<p>
Solr is a Search Service...
jQuery controls the DOM elements...
</p>
</div>
</div>
<div class="item">
<img src="images/logo/scrapy.jpg" class="img-rounded">
<img src="images/logo/bootstrap.png" class="img-rounded">
<div class="carousel-caption">
<h4>Scrapy</h4>
<h4>Bootstrap</h4>
<p>
Scrapy is a web crawler...
Boostrap is a tool to design the website...
</p>
</div>
</div>
@@ -67,11 +86,11 @@
<img src="images/logo/bootstrap.png" class="img-polaroid">
<img src="images/logo/jquery.png" class="img-polaroid">
<img src="images/logo/mongodb.png" class="img-polaroid">
<img src="images/logo/struts2.png" class="img-polaroid">
<img src="images/logo/struts2.jpg" class="img-polaroid">
<br />
<img src="images/logo/scrapy.jpg" class="img-polaroid">
<img src="images/logo/solr.png" class="img-polaroid">
<img src="images/logo/lucene.png" class="img-polaroid">
<img src="images/logo/lucene.jpg" class="img-polaroid">
<img src="images/logo/tika.png" class="img-polaroid">
<br />
<img src="images/logo/tomcat.jpg" class="img-circle">
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

+8 -2
View File
@@ -14,7 +14,7 @@
<link href="css/index.css" rel="stylesheet" />
</head>
<body>
<!-- navbar -->
<!-- smallhead -->
<div class="navbar navbar-inverse">
<div class="navbar-inner">
<a class="brand" href="#">Academic Search</a>
@@ -52,7 +52,7 @@
</div>
<!-- 搜索框 -->
<div class="container" id="myhead">
<div class="container">
<div class="hero-unit">
<form class="form-search" action="academic">
<input type="text" class="input-xxlarge control-group info" placeholder="您的搜索关键词" name="key">
@@ -192,5 +192,11 @@
<input id="skey" type=hidden value="<s:property value="key" />" ></input>
<input id="stype" type=hidden value="<s:property value="core" />" ></input>
<!--
<s:url action="hello" var="helloLink">
<s:param name="userName">参数值</s:param>
</s:url>
<p><a href="${helloLink}">这也是一种控制</a></p>
-->
</body>
</html>
+5 -38
View File
@@ -1,7 +1,6 @@
$(function() {
// 载入时启动的默认函数
leftSide();
// colorfy(document.body, $("#skey").val());
// 行为绑定
$(".author_tooltip").on("mouseover", function(e) {
@@ -24,8 +23,7 @@ function leftSide() {
function showFields() {
var name = $("#skey").val();
if (name != "") {
var url = "http://localhost:8080/AcademicSearchEngine/field?name="
+ name;
var url = "http://localhost:8080/AcademicSearchEngine/field?name=" + name;
$.ajax({
type : 'GET',
url : url,
@@ -34,9 +32,7 @@ function showFields() {
var fieldlist = data.fields;
var len = fieldlist.length;
for ( var i = 0; i < len; i++) {
$("#fieldBar").append(
'<div class="accordion-inner">' + fieldlist[i]
+ '</div>');
$("#fieldBar").append('<div class="accordion-inner">' + fieldlist[i] + '</div>');
}
},
error : function(XmlHttpRequest, textStatus, errorThrown) {
@@ -49,8 +45,7 @@ function showFields() {
function showPlaces() {
var name = $("#skey").val();
if (name != "") {
var url = "http://localhost:8080/AcademicSearchEngine/place?name="
+ name;
var url = "http://localhost:8080/AcademicSearchEngine/place?name=" + name;
$.ajax({
type : 'GET',
url : url,
@@ -59,9 +54,7 @@ function showPlaces() {
var placelist = data.places;
var len = placelist.length;
for ( var i = 0; i < len; i++) {
$("#placeBar").append(
'<div class="accordion-inner">' + placelist[i]
+ '</div>');
$("#placeBar").append('<div class="accordion-inner">' + placelist[i] + '</div>');
}
},
error : function(XmlHttpRequest, textStatus, errorThrown) {
@@ -69,30 +62,4 @@ function showPlaces() {
}
});
}
}
//function colorfy(n, k) {
//
// var cs = n.childNodes;
// var i = 0, l = cs.length;
// var t, c, pos, rest;
// t = document.createElement('font');
// t.color = 'red';
// t.innerHTML = k;
//
// for (; i < l; i++) {
// c = cs[i];
// if (c.nodeType == 3) {
// t = t.cloneNode(true);
//
// pos = c.nodeValue.indexOf(k);
// if (pos != -1) {
// rest = c.splitText(pos);
// rest.replaceData(0, k.length, '');
// n.insertBefore(t, rest);
// }
//
// } else
// yit(cs[i], k);
// }
//}
}
File diff suppressed because one or more lines are too long
+165
View File
@@ -0,0 +1,165 @@
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="js/jquery-1.7.2.js"></script>
<script src="js/index.js"></script>
<script src="bootstrap/js/bootstrap.min.js"></script>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="css/index.css" rel="stylesheet" />
<style>
.background {
fill: #eee;
}
line {
stroke: #fff;
}
text.active {
fill: red;
}
</style>
<script src="http://d3js.org/d3.v2.min.js?2.8.1"></script>
</head>
<body>
<div class="container">
<select id="order">
<option value="name">by Name</option>
<option value="count">by Frequency</option>
<option value="group">by Cluster</option>
</select>
</div>
<div class="container" id="pic">
</div>
<script>
var margin = {
top : 80,
right : 0,
bottom : 10,
left : 80
}, width = 800, height = 800;
var x = d3.scale.ordinal().rangeBands([ 0, width ]),
z = d3.scale.linear().domain([ 0, 4 ]).clamp(true),
c = d3.scale.category10().domain(d3.range(10));
var svg = d3.select("#pic").append("svg").attr("width", width + margin.left + margin.right).attr("height",
height + margin.top + margin.bottom).style("margin-left", -margin.left + "px").append("g").attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
d3.json(
"http://localhost:8080/AcademicSearchEngine/test.json", function(miserables) {
var matrix = [], nodes = miserables.nodes, n = nodes.length;
// Compute index per node.
nodes.forEach(function(node, i) {
node.index = i;
node.count = 0;
matrix[i] = d3.range(n).map(function(j) {
return { x : j, y : i, z : 0};
});
});
// Convert links to matrix; count character occurrences.
miserables.links.forEach( function(link) {
matrix[link.source][link.target].z += link.value;
matrix[link.target][link.source].z += link.value;
matrix[link.source][link.source].z += link.value;
matrix[link.target][link.target].z += link.value;
nodes[link.source].count += link.value;
nodes[link.target].count += link.value;
});
// Precompute the orders.
var orders = {
name : d3.range(n).sort(function(a, b) {
return d3.ascending(nodes[a].name, nodes[b].name);
}),
count : d3.range(n).sort(function(a, b) {
return nodes[b].count - nodes[a].count;
}),
group : d3.range(n).sort(function(a, b) {
return nodes[b].group - nodes[a].group;
})
};
// The default sort order.
x.domain(orders.name);
svg.append("rect").attr("class", "background").attr("width", width).attr("height", height);
var row = svg.selectAll(".row").data(matrix).enter().append("g").attr("class", "row").attr("transform",
function(d, i) {return "translate(0," + x(i) + ")";}).each(row);
row.append("line").attr("x2", width);
row.append("text").attr("x", -6).attr("y", x.rangeBand() / 2).attr("dy", ".32em").attr("text-anchor", "end").text(
function(d, i) {return nodes[i].name;});
var column = svg.selectAll(".column").data(matrix).enter().append("g").attr("class", "column").attr(
"transform", function(d, i) {return "translate(" + x(i)+ ")rotate(-90)";});
column.append("line").attr("x1", -width);
column.append("text").attr("x", 6).attr("y",x.rangeBand() / 2).attr("dy", ".32em").attr("text-anchor", "start").text(
function(d, i) {return nodes[i].name;});
function row(row) {
var cell = d3.select(this).selectAll(".cell").data(row.filter(function(d) {
return d.z;
})).enter().append("rect").attr("class", "cell").attr("x", function(d) {
return x(d.x);
}).attr("width", x.rangeBand()).attr("height", x.rangeBand()).style("fill-opacity", function(d) {
return z(d.z);
}).style("fill", function(d) {
return nodes[d.x].group == nodes[d.y].group ? c(nodes[d.x].group): null;
}).on("mouseover", mouseover).on("mouseout", mouseout);
}
function mouseover(p) {
d3.selectAll(".row text").classed("active", function(d, i) {return i == p.y;});
d3.selectAll(".column text").classed("active",function(d, i) {return i == p.x;});
}
function mouseout() {
d3.selectAll("text").classed("active", false);
}
d3.select("#order").on("change", function() {
clearTimeout(timeout);
order(this.value);
});
function order(value) {
x.domain(orders[value]);
var t = svg.transition().duration(2500);
t.selectAll(".row").delay(function(d, i) {
return x(i) * 4;
}).attr("transform", function(d, i) {
return "translate(0," + x(i) + ")";
}).selectAll(".cell").delay(function(d) {
return x(d.x) * 4;
}).attr("x", function(d) {
return x(d.x);
});
t.selectAll(".column").delay(function(d, i) {
return x(i) * 4;
}).attr("transform", function(d, i) {
return "translate(" + x(i) + ")rotate(-90)";
});
}
var timeout = setTimeout(function() {
order("group");
d3.select("#order").property("selectedIndex", 2).node().focus();
}, 5000);
});
</script>
</body>
</html>
@@ -18,6 +18,7 @@ import zbf.search.model.PublicationModel;
import zbf.search.util.StdOutUtil;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
@@ -58,14 +59,10 @@ public class PublicationIndex {
BasicDBList list = (BasicDBList) obj.get("author");
String s = "";
for (int i = 0; i < list.size(); i ++) {
if (list.get(i).toString().length() > 1) {
String tmp = (String) list.get(i);
tmp = tmp.replace(",", "");
if (s == "") {
s = tmp;
} else {
s = s + ", " + tmp;
}
if (s.equals("")) {
s = (String) list.get(i);
} else {
s = s + ", " + (String) list.get(i);
}
}
StdOutUtil.out(s);
@@ -4,6 +4,7 @@ import java.net.UnknownHostException;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.MongoClient;
public class MyMongoClient {
@@ -31,4 +32,7 @@ public class MyMongoClient {
return mongodb.getCollection(coll);
}
public static void main(String[] args) {
}
}
@@ -1,46 +1,201 @@
package zbf.search.recommend;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import zbf.search.mongodb.MyMongoClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import net.sf.json.JSONObject;
import zbf.search.solrj.SolrjClient;
import zbf.search.util.StdOutUtil;
import zbf.search.util.StringUtil;
import com.mongodb.BasicDBList;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
public class BtwAuthor {
public static void main(String[] args) throws IOException {
MyMongoClient mongoClient = new MyMongoClient("researchers");
DBCollection coll = mongoClient.getDBCollection();
BtwAuthor ba = new BtwAuthor();
//ArrayList<String> list = ba.findCoAuthorsByName("Noga Alon", 0, 300);
ArrayList<String> list = ba.findCoAuthorsByPaper("data mining", 0, 200);
StdOutUtil.out(ba.getCoauthorJson(list));
}
ArrayList<String> doc1 = new ArrayList<String>();
ArrayList<String> doc2 = new ArrayList<String>();
DBObject target = coll.findOne();
BasicDBList tmp = (BasicDBList) target.get("field");
String target_field = StringUtil.filterAmp(tmp.toString());
StdOutUtil.out(target.get("name"));
StdOutUtil.out(target_field);
doc1 = StringUtil.getTokens(target_field);
DBCursor cursor = coll.find();
while (cursor.hasNext()) {
DBObject obj = cursor.next();
BasicDBList fields = (BasicDBList) obj.get("field");
String field = StringUtil.filterAmp(fields.toString());
if (field.length() > 3) {
//StdOutUtil.out(field);
doc2 = StringUtil.getTokens(field);
double sim = CosineDis.getSimilarity(doc1, doc2);
if (sim == 1.0) {
StdOutUtil.out(sim);
public ArrayList<String> findCoAuthorsByPaper(String text, int start, int rows) throws UnknownHostException {
ArrayList<String> coworkers = new ArrayList<String>();
SolrjClient client = new SolrjClient(1);
SolrServer server = client.getSolrServer();
SolrQuery query = new SolrQuery();
query.setQuery((StringUtil.transformQuery("title", text))+(StringUtil.transformQuery("pub_abstract", text)));
query.setStart(start);
query.setRows(rows);
QueryResponse rsp;
try {
rsp = server.query(query);
SolrDocumentList docs = rsp.getResults();
for (SolrDocument doc : docs) {
String s = (String) doc.getFieldValue("author");
String[] ss = s.split(", ");
for (String tmp : ss) {
if (!coworkers.contains(tmp))
coworkers.add(tmp);
}
}
} catch (SolrServerException e) {
e.printStackTrace();
}
Collections.sort(coworkers);
StdOutUtil.out(coworkers.size());
return coworkers;
}
public ArrayList<String> findCoAuthorsByName(String name, int start, int rows) throws UnknownHostException {
ArrayList<String> coworkers = new ArrayList<String>();
SolrjClient client = new SolrjClient(1);
SolrServer server = client.getSolrServer();
SolrQuery query = new SolrQuery();
query.setQuery((StringUtil.transformQuery("author", name)));
query.setStart(start);
query.setRows(rows);
QueryResponse rsp;
try {
rsp = server.query(query);
SolrDocumentList docs = rsp.getResults();
for (SolrDocument doc : docs) {
String s = (String) doc.getFieldValue("author");
String[] ss = s.split(", ");
for (String tmp : ss) {
if (!coworkers.contains(tmp)) {
coworkers.add(tmp);
}
}
}
} catch (SolrServerException e) {
e.printStackTrace();
}
Collections.sort(coworkers);
StdOutUtil.out(coworkers.size());
return coworkers;
}
public Map<String, Integer> coauthorNodes(ArrayList<String> list) throws UnknownHostException{
Map<String, String> nameMap = new HashMap<String, String>();
Map<String, Integer> placeMap = new HashMap<String, Integer>();
Map<String, Integer> nodeMap = new TreeMap<String, Integer>();
SolrjClient client = new SolrjClient(0);
SolrServer server = client.getSolrServer();
for (String name : list) {
SolrQuery query = new SolrQuery();
query.setQuery((StringUtil.transformQuery("name", name)));
query.setStart(0);
query.setRows(1);
QueryResponse rsp;
try {
rsp = server.query(query);
SolrDocumentList docs = rsp.getResults();
for (SolrDocument doc : docs) {
String workplace = (String) doc.getFieldValue("workplace");
nameMap.put(name, workplace);
if(!placeMap.containsKey(workplace)) {
placeMap.put(workplace, placeMap.keySet().size());
}
nodeMap.put(name, placeMap.get(nameMap.get(name)));
break;
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
StdOutUtil.out("[nodeMap]: "+nodeMap.toString());
StdOutUtil.out("[nodeMap]: "+nodeMap.keySet().size());
return nodeMap;
}
public Map<Integer[], Integer> coauthorLinks(Map<String, Integer> nodeMap) throws IOException {
Map<Integer[], Integer> linkMap = new HashMap<Integer[], Integer>();
Map<String, Integer> numMap = new HashMap<String, Integer>();
Iterator<String> iterator = nodeMap.keySet().iterator();
while (iterator.hasNext()) {
String s = iterator.next();
numMap.put(s, numMap.size());
}
// find co-pdfs-count
Set<String> list = numMap.keySet();
for (String name : list) {
int i = numMap.get(name);
for (String other : list) {
if (other != name) {
SolrjClient client = new SolrjClient(1);
SolrServer server = client.getSolrServer();
SolrQuery query = new SolrQuery();
query.setQuery((StringUtil.transformIK("author", name+" "+other)));
QueryResponse rsp;
try {
rsp = server.query(query);
SolrDocumentList docs = rsp.getResults();
if (docs.size() > 0) {
String[] s = {name, other};
Integer[] array = {i, numMap.get(other)};
linkMap.put(array, docs.size());
StdOutUtil.out(docs.size());
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
}
}
StdOutUtil.out("[linkMap]: "+linkMap.size());
return linkMap;
}
public JSONObject getCoauthorJson(ArrayList<String> list) throws IOException {
BtwAuthor author = new BtwAuthor();
Map<String, Integer> nodeMap = author.coauthorNodes(list);
Map<Integer[], Integer> linkMap = author.coauthorLinks(nodeMap);
JSONObject json = new JSONObject();
Iterator<String> iterator1 = nodeMap.keySet().iterator();
List<JSONObject> jsonlist1 = new ArrayList<JSONObject>();
while (iterator1.hasNext()) {
String name = iterator1.next();
int group = nodeMap.get(name);
JSONObject tmp = new JSONObject();
tmp.put("name", name);
tmp.put("group", group);
jsonlist1.add(tmp);
}
json.put("nodes", jsonlist1);
Iterator<Integer[]> iterator2 = linkMap.keySet().iterator();
List<JSONObject> jsonlist2 = new ArrayList<JSONObject>();
while (iterator2.hasNext()) {
Integer[] ns = iterator2.next();
int value = linkMap.get(ns);
JSONObject tmp = new JSONObject();
tmp.put("source", ns[0]);
tmp.put("target", ns[1]);
tmp.put("value", value);
jsonlist2.add(tmp);
}
json.put("links", jsonlist2);
return json;
}
}
@@ -1,41 +1,55 @@
package zbf.search.recommend;
import java.io.IOException;
import java.util.ArrayList;
import java.net.UnknownHostException;
import zbf.search.mongodb.MyMongoClient;
import zbf.search.util.StdOutUtil;
import zbf.search.util.StringUtil;
import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
public class BtwPublication {
public static void main(String[] args) throws IOException{
MyMongoClient mongoClient = new MyMongoClient("publications");
DBCollection coll = mongoClient.getDBCollection();
ArrayList<String> doc1 = new ArrayList<String>();
ArrayList<String> doc2 = new ArrayList<String>();
DBObject target = coll.findOne();
StdOutUtil.out(target.get("title"));
StdOutUtil.out(target.get("abstract"));
doc1 = StringUtil.getTokens((String) target.get("abstract"));
DBCursor cursor = coll.find();
BtwPublication bp = new BtwPublication();
//bp.updatePublicationForComma();
}
public void updatePublicationForComma() throws UnknownHostException {
MyMongoClient client = new MyMongoClient("publications");
DBCollection collection = client.getDBCollection();
DBCursor cursor = collection.find(new BasicDBObject("author", new BasicDBObject("$regex", ".*,.*")));
StdOutUtil.out(cursor.size());
while (cursor.hasNext()) {
DBObject obj = cursor.next();
String s = (String) obj.get("abstract");
if (s.length() > 3) {
doc2 = StringUtil.getTokens(s);
double sim = CosineDis.getSimilarity(doc1, doc2);
if (sim > 0.55 && sim != 1.0) {
StdOutUtil.out(sim);
StdOutUtil.out(s);
}
String title = (String) obj.get("title");
String conference = (String) obj.get("conference");
BasicDBList author = (BasicDBList) obj.get("author");
String view_url = (String) obj.get("view_url");
String abst = (String) obj.get("abstract");
collection.remove(new BasicDBObject("title", title));
StdOutUtil.out("[DEL]: " + author.toString());
BasicDBList newauthor = new BasicDBList();
for (int i = 0; i < author.size(); i ++) {
String tmp = (String) author.get(i);
tmp = tmp.replace(", ", "");
tmp = tmp.replace(",", "");
newauthor.add(tmp);
}
DBObject newobj = new BasicDBObject();
newobj.put("title", title);
newobj.put("conference", conference);
newobj.put("author", newauthor);
newobj.put("view_url", view_url);
newobj.put("abstract", abst);
collection.save(newobj);
StdOutUtil.out("[ADD]: " + newauthor.toString());
}
}
}
@@ -10,6 +10,7 @@ import java.util.ArrayList;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
public class StringUtil {
public static boolean isBlank(String str) {
int strLen;
@@ -76,6 +77,28 @@ public class StringUtil {
return qq;
}
public static String transformIK(String field, String target) throws IOException {
InputStream is = new ByteArrayInputStream(target.getBytes("UTF-8"));
BufferedReader input = new BufferedReader(new InputStreamReader(is));
// true为智能划词, false为最细粒度划词
IKSegmenter segmenter = new IKSegmenter(input, true);
Lexeme token = null;
String qq = "";
do {
token = segmenter.next();
if (token != null) {
if (!qq.equals("")) {
qq = qq + " " + field + ":" + token.getLexemeText();
} else {
qq = field + ":" + token.getLexemeText();
}
}
} while (token != null);
return qq;
}
public static ArrayList<String> ArrayToArrayList(String[] objs) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < objs.length; i ++) {