package com.nnn.m.service;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.spatial.SpatialStrategy;
import org.apache.lucene.spatial.prefix.RecursivePrefixTreeStrategy;
import org.apache.lucene.spatial.prefix.tree.GeohashPrefixTree;
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
import org.apache.lucene.spatial.query.SpatialArgs;
import org.apache.lucene.spatial.query.SpatialOperation;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import com.nnn.m.dao.LuceneSearchDao;
import com.nnn.m.dao.impl.LuceneSearchDaoImpl;
import com.nnn.m.pojo.LuceuePOI;
import com.nnn.m.pojo.ResultPojo;
import com.nnn.m.pojo.SearchPojo;
import com.nnn.tools.SearchUtils;
import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.shape.Shape;
public class LuceneSearchService {
private static Log log = LogFactory.getLog(LuceneSearchDaoImpl.class);
private static boolean logOperation = false;
private LuceneSearchDao dao = new LuceneSearchDaoImpl();
// Spatial
private SpatialContext ctx = SpatialContext.GEO;
private SpatialStrategy strategy;
private Directory directory;
public LuceneSearchService(String fieldName, String indexPath) {
SpatialPrefixTree grid = new GeohashPrefixTree(ctx, SearchUtils.MAX_LEVELS);
this.strategy = new RecursivePrefixTreeStrategy(grid, fieldName);
try {
File file = new File(indexPath);
if (file.exists() && file.isDirectory()) {
} else {
file.mkdir();
}
this.directory = FSDirectory.open(new File(indexPath));
} catch (IOException e) {
if (logOperation) {
log.debug(e.getMessage());
}
e.printStackTrace();
}
}
// 初始化并创建
// 创建索引
public void writeIndex(String filePath) throws IOException {
Properties prop = new Properties();
BufferedReader reader = null;
Analyzer analyzer = new SmartChineseAnalyzer(Version.LUCENE_48);
try {
// 读取配置文件并对document对象赋值
prop.load(LuceneSearchService.class.getResourceAsStream("file_init.properties"));
reader = new BufferedReader(new FileReader(filePath));
List<Document> documents = new ArrayList<Document>();
while (reader.ready()) {
Document document = new Document();
String line = reader.readLine();
if (line != null && line.length() > 1 && !line.contains("PVID")) {
String[] tempLine = line.substring(1).split("\",\"");
String pvid = tempLine[Integer.parseInt(prop.getProperty("pvid"))];
String name = tempLine[Integer.parseInt(prop.getProperty("name"))];
String tag1 = tempLine[Integer.parseInt(prop.getProperty("tag1"))];
String tag2 = tempLine[Integer.parseInt(prop.getProperty("tag2"))];
String tel = tempLine[Integer.parseInt(prop.getProperty("tel"))];
String address = tempLine[Integer.parseInt(prop.getProperty("address"))];
String nav_x = tempLine[Integer.parseInt(prop.getProperty("nav_x"))];
String nav_y = tempLine[Integer.parseInt(prop.getProperty("nav_y"))];
Field f_pvid = new StringField(LuceuePOI.PVID, pvid, Field.Store.YES);
Field f_name = new StringField(LuceuePOI.NAME, name, Field.Store.YES);
Field f_tag1 = new StringField(LuceuePOI.TAG1, tag1, Field.Store.YES);
Field f_tag2 = new StringField(LuceuePOI.TAG2, tag2, Field.Store.YES);
Field f_address = new StringField(LuceuePOI.ADDRESS, address, Field.Store.YES);
Field f_tel = new StringField(LuceuePOI.TEL, tel, Field.Store.YES);
// Field f_nav_x = new LongField(LuceuePOI.NAV_X,
// NumericUtils.doubleToSortableLong(Double.parseDouble(nav_x)),
// Field.Store.YES);
// Field f_nav_y = new LongField(LuceuePOI.NAV_X,
// NumericUtils.doubleToSortableLong(Double.parseDouble(nav_y)),
// Field.Store.YES);
document.add(f_pvid);
document.add(f_name);
document.add(f_tag1);
document.add(f_tag2);
document.add(f_address);
document.add(f_tel);
buildDocument(document, ctx.makePoint(Double.parseDouble(nav_x), Double.parseDouble(nav_y)));
documents.add(document);
if (documents.size() > 102400) {
dao.createIndex(documents, directory, analyzer);
documents.clear();
}
}
}
if (documents.size() > 0) {
dao.createIndex(documents, directory, analyzer);
documents.clear();
}
} catch (IOException e) {
if (logOperation) {
log.debug(e.getMessage());
}
e.printStackTrace();
} finally {
reader.close();
}
}
private Document buildDocument(Document doc, Shape... shapes) {
for (Shape shape : shapes) {
for (IndexableField f : strategy.createIndexableFields(shape)) {
doc.add(f);
}
doc.add(new StoredField(strategy.getFieldName(), ctx.toString(shape)));
}
return doc;
}
public List<ResultPojo> search(SearchPojo searchPojo) throws IOException {
List<ResultPojo> resultList = new ArrayList<ResultPojo>();
IndexReader indexReader = DirectoryReader.open(directory);
SpatialArgs args = new SpatialArgs(SpatialOperation.Intersects, ctx.makeCircle(searchPojo.getLat(), searchPojo.getLon(),
DistanceUtils.dist2Degrees(searchPojo.getRange(), DistanceUtils.EARTH_MEAN_RADIUS_KM)));
Filter filter = strategy.makeFilter(args);
Term term = new Term(searchPojo.getKeyWord(), searchPojo.getKeyValue());
Query query = new TermQuery(term);
TopDocs docs = dao.search(indexReader, query, filter, searchPojo.getNeedToSearchCount());
System.out.println(docs.totalHits);
ScoreDoc[] scoreDoc = docs.scoreDocs;
if (docs.totalHits > 0) {
for (int i = 0; i < scoreDoc.length; i++) {
int doc = scoreDoc[i].doc;
Document mydoc = indexReader.document(doc);
String value = mydoc.get("poiSearch");
String[] lonlat = value.split(" ");
double eLat = Double.valueOf(lonlat[0]);
double eLon = Double.valueOf(lonlat[1]);
LuceuePOI lp = new LuceuePOI();
lp.setName(mydoc.get("name"));
lp.setPvid(mydoc.get("pvid"));
lp.setTag1(mydoc.get("tag1"));
lp.setTag2(mydoc.get("tag2"));
lp.setAddress(mydoc.get("address"));
lp.setTel(mydoc.get("tel"));
lp.setNav_x(lonlat[0]);
lp.setNav_y(lonlat[1]);
ResultPojo rp = new ResultPojo();
rp.setDistance(SpatialUtils.getDistance(Double.valueOf(searchPojo.getLat()), Double.valueOf(searchPojo.getLon()), eLat, eLon) + "");
rp.setLucenePoi(lp);
resultList.add(rp);
}
}
Collections.sort(resultList, new SearchSort());
indexReader.close();
return resultList;
}
}
class SearchSort implements Comparator<ResultPojo> {
public int compare(ResultPojo r1, ResultPojo r2) {
int sort = r1.getDistance().compareTo(r2.getDistance());
if (sort == 0) {
sort = r1.getLucenePoi().getName().compareToIgnoreCase(r2.